如何在不通过类的情况下使用QtMenu或QtMoseEvent

问题描述

你好,我在用python开发软件,我不是很好,到目前为止,我还没有在程序中使用任何类。 我想用鼠标做事件而不需要上课,而我发现的所有代码都使用了上课,在不破坏程序的情况下我很难使用它。

这是我的代码

def init_tree(win):
    tw = QTreeWidget(win)
    tw.resize(500,500)

    tw.setHeaderLabels(['TAGS'])
    tw.setAlternatingRowColors(True)

    tw = clear_tree(tw)
    fill_tree(tw)

    tw.show()

def main():
    app = QApplication.instance()
    if not app:
        app = QApplication(argv)

    window  = widgets()

    init_tree(window)

    mouse_press_event(window)

    exit(app.exec_())
main()

这是我要添加代码

def contextMenuEvent(self,event):
        contextMenu = QMenu(self)
        newAct = contextMenu.addAction("New")
        openAct = contextMenu.addAction("Open")
        quitact = contextMenu.addAction("Quit")
        action = contextMenu.exec_(self.mapToGlobal(event.pos()))
        if action == quitact:
            self.close()

OR

class MyWidget(QWidget):


    def __init__(self):
        super(MyWidget,self).__init__()

    def mousepressEvent(self,QMouseEvent):
        if QMouseEvent.button() == Qt.LeftButton:
            print("Left Button Clicked")
        elif QMouseEvent.button() == Qt.RightButton:
            #do what you want here
            print("Right Button Clicked")

对于自我,我将win作为参数传递

我遇到的麻烦是“ event / QMouseEvent”参数

解决方法

它可以部分完成,通常称为 monkey patching ,这是一段扩展或修改其他代码的Python代码。

但是,您无法像使用init_tree函数那样对事件进行管理:这些函数是“静态的”,因为它们仅被调用一次,而事件驱动的函数应在相关事件被调用时被调用。发出。

然后的解决方案是使用对那些事件做出反应的函数“猴子补丁”类实例。这是一个简单的示例:

def mouse_press_event(event):
    print('mouse pressed',event.pos())

some_widget.mousePressEvent = mouse_press_event

现在,有一个陷阱。 ALL 实例方法的第一个参数是对 instance 的引用,这就是self的含义(请注意,“ self”只是一个约定,您可以随便命名)。这是因为实例方法通常需要对实例进行 操作。在您提供的contextMenuEvent代码中,这很明显:self对于设置菜单的父级非常重要,最重要的是要使用其mapToGlobal

当您使用上面的匿名函数进行猴子补丁时,您没有第一个实例参数(实际上,我们只有event参数)。为了实现这一点,通过“匿名”猴子修补,我们必须人为地提供实例参数,我们可以为此使用lambda

def contextMenuEvent(self,event):
        contextMenu = QMenu(self)
        # ...
        action = contextMenu.exec_(event.globalPos())
        # ...

some_widget.contextMenuEvent = lambda event: contextMenuEvent(tw,event)

注意:我直接使用event.globalPos()更改了您的代码;原因是所有QAbstractScrollArea子类(例如QTreeWidget的所有QAbstractItemView子类)都具有一个子“视口”,该子视口实际上显示了要滚动的内容,并且视口有时会被某些像素转换,例如在显示标题时。

原始功能应更改为此:

action = contextMenu.exec_(self.viewport().mapToGlobal(event.pos()))

但是我们显然不需要,因为所有鼠标事件还具有一个globalPos(),它已经映射到全局坐标。

最后,虽然在某些情况下您的方法是理想的(通常使用临时实例在运行时非常简单地重新实现),但是如果您要为整个程序这样做,应该考虑四个方面:

  • 这是个坏主意;
  • 您不应那样做,而应使用子类;
  • 除非您真的 知道自己在做什么以及为什么这样做,否则您真的不应该这样做;
  • 这是一个真的坏主意;

如果您认为采用这种方法可以使事情变得轻松,对不起,但是您错了:有时您的程序会变得过于复杂,而所有匿名用户只会使您的程序非常很难进行读取和调试。

与其找到复杂且不合常规的方法来以一种不应该做的方式做某事,而要学习以正确的方式做这件事。

作为进一步的说明,猴子修补程序在PyQt中存在一个重要的问题:Qt使用函数缓存来加快处理速度并使用更少的资源,并且如果首先使用已经存在的基本方法调用函数,猴子修补程序将无法在所有,因为第一个原始方法将始终在之后被调用。

因此,花一些时间,学习如何创建子类,不仅会发现它们比看起来更简单,而且会大大改善您的编码。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...