0

你好我正在用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()

或者

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 作为参数传递

我遇到的问题是“事件/ QMouseEvent”参数

4

1 回答 1

0

它可以部分完成,它通常被称为猴子补丁,它是一段 Python 代码,它扩展或修改了其他代码。

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

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

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

some_widget.mousePressEvent = mouse_press_event

现在,有一个问题。所有实例方法都有一个第一个参数,它是对实例的引用,就是这样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 子类(就像所有 QAbstractItemView 子类作为 QTreeWidget 一样)都有一个子“视口”,它实际上显示了将要滚动的内容,并且该视口有时会被某些像素转换,例如在显示标题时。

原来的功能应该改成这样:

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

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

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

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

如果您认为遵循这种方法可能会使事情变得容易,那么对不起,您错了:在某些时候您的程序会变得过于复杂,所有这些匿名只会使您的程序非常难以阅读和调试。

与其寻找复杂和非正统的方法以不应该做的方式做某事,不如学会以正确的方式做事。

进一步说明,猴子补丁在 PyQt 中存在一个重要问题:Qt 使用函数缓存来加快速度并使用更少的资源,如果首先使用已经存在的基本方法调用函数,猴子补丁将根本不起作用,因为之后总是会调用第一个原始方法。

所以,慢慢来,学习如何创建子类,你不仅会发现它们比看起来更容易,而且会显着改善你的编码。

于 2020-10-21T20:11:18.043 回答