【问题标题】:Python: How to correctly use external functionsPython:如何正确使用外部函数
【发布时间】:2012-06-16 18:11:24
【问题描述】:

这是我看过很多文档的东西,但我无法对我的知识上的这个特定差距给出确切的答案,因此我一直在碰壁,似乎没有什么能真正涵盖它等级:

我有几个窗口,它们都应该是可拖动的,所以我正在构建一个实用程序文件。在这个文件中我有这个:

def mouseMoveEvent(self, event):
    if self.moving: self.move(event.globalPos()-self.offset)

def mousePressEvent(self, event):
    if event.button() == QtCore.Qt.LeftButton:
        self.moving = True; self.offset = event.pos()


def mouseReleaseEvent(self, event):
    if event.button() == QtCore.Qt.LeftButton:
        self.moving = False

如果我将它放入带有实际窗口的单个文件中(并且不要从另一个文件调用),这将起作用。

问题是,我如何从另一个文件(具有 UI 窗口的文件)调用它?

我打电话给它

 from utils import *

所以从技术上讲,这些功能都可以通过键入来访问

mouseReleaseEvent(x,x)

但我需要 UI 来导入这些功能,所以在主文件中放置“from utils import *”后输入:

self.moving = False

但是无论我做什么都会出错。所以问题是什么是封装首先列出的函数(第一个代码块)以便我可以从我的 UI 文件中调用它们的正确方法?

这是我的用户界面代码:

    #!/usr/bin/env python

    import sys
    import os
    from PyQt4 import QtCore, QtGui
    from vibotCss import css
    from viUtils import *

    class viBadOSUI(QtGui.QDialog):
        def __init__(self):
            QtGui.QDialog.__init__(self)
            #setup window
            self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
            self.resize(300, 150)
            center(self)
            self.setMouseTracking(True)



            #additional code
            self.show()
            self.setStyleSheet(css)



    app = QtGui.QApplication(sys.argv)
    window = viBadOSUI()
    sys.exit(app.exec_())

由于长期以来仅在 Autodesk Maya 中学习和使用 Python,我的 Python 知识存在很大差距 - 我现在正试图弥合上述差距。感谢您的帮助。

【问题讨论】:

    标签: python class function import pyqt


    【解决方案1】:

    我认为您正在寻找的是 mixins:

    例如,在 viUtils.py 中,您可以定义:

    from PyQt4 import QtCore, QtGui
    
    class Draggable(object):
        def mouseMoveEvent(self, event):
            try:
                if self.moving:
                    self.move(event.globalPos()-self.offset)
            except AttributeError:
                pass
    
        def mousePressEvent(self, event):
            if event.button() == QtCore.Qt.LeftButton:
                self.moving = True; self.offset = event.pos()
    
        def mouseReleaseEvent(self, event):   
            if event.button() == QtCore.Qt.LeftButton:
                self.moving = False
    
    class Centerable(object):
        pass # add code here
    
    class CountdownTimer(object):
        pass # add code here
    

    通过将相关方法捆绑在 mixins 中,您可以通过简单地将 mixin(s) 添加到基类中来为类(窗口)添加功能:

    import sys
    import os
    from PyQt4 import QtCore, QtGui
    from vibotCss import css
    import viUtils
    
    class viBadOSUI(QtGui.QDialog, 
                    viUtils.Draggable, viUtils.CountdownTimer):
    
        def __init__(self):            
            QtGui.QDialog.__init__(self)
            #setup window
            self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
            self.resize(300, 150)
            center(self)  # You should probably make `center` a method instead of a function and call `self.center()` instead.
            self.setMouseTracking(True)
    
            #additional code
            self.show()
            self.setStyleSheet(css)
    
    app = QtGui.QApplication(sys.argv)
    window = viBadOSUI()
    sys.exit(app.exec_())
    

    我不喜欢上面的代码的一点是,我不知道如何用__init__ 定义一个mixin(例如Draggable),它会被viBadOSUI.__init__ 自动调用。通常你会为此使用super,但似乎QtGui.QDialog.__init__ 本身并不调用super

    (实际上,我认为可以使用super 如果你把mixins 之前 QtGui.QDialog,但这依赖于诡计,会破坏一次有人忘记了QtGui.QDialog 必须出现在碱基列表的最后。)

    因为我无法定义可以稳定工作的__init__ 方法:

    class Draggable(object):
        def __init__(self):
            ...
            self.moving = False
    

    我改为修改mouseMoveEvent 以使用try..except。 这比将self.moving = False 直接添加到viBadOSUI.__init__ 更好,因为此属性仅由 Draggable 使用,因此应该以某种方式与Draggable 捆绑在一起。设置 mixin 然后必须记住初始化一个属性才能使 mixin 工作是丑陋的编程。

    在这里使用try..except 可能比使用if hasattr(self, 'moving') 稍微好一点,因为只要不引发异常,try 会更快,并且只会在第一个mousePressEvent 之前的开头引发异常。

    不过,还有改进的余地,我希望这里有人能告诉我们更好的方法。

    另一种方法是定义

    class viBadOSUI(QtGui.QDialog):
        mouseMoveEvent = viUtils.mouseMoveEvent
        mousePressEvent = viUtils.mousePressEvent
        mouseReleaseEvent = viUtils.mouseReleaseEvent
    

    这为您提供了很大的灵活性,可以将 viUtils 中所需的方法直接添加到您定义的任何类中。但是,我认为它有点过于灵活,因为 mouseMoveEvent、mousePressEvent 和 mouseReleaseEvent 对我来说似乎是“捆绑”的。它们一起工作以实现单个功能。这就是为什么我更喜欢 mixin 方法的原因。此外,将viUtils.Draggable 添加到基类比将这 3 行添加到您希望可拖动的每个窗口子类要少。

    顺便说一句,我建议不要使用from viUtils import *,而是使用import viUtils。从长远来看,这将使您的代码更有条理。

    【讨论】:

    • 您好,感谢您抽出宝贵时间回复。我实际上仍然很迷茫,但我照你说的做了,结果错误是:RuntimeError:底层 C/C++ 对象已被删除——这可能是由于行 'viUtils.viDragUI.__init__(self)' 造成的。
    • 我测试了我发布的代码。我工作(如果你注释掉center(self)self.setStyleSheet(css)——我假设你在别处定义了这些)。所以我不确定你为什么遇到RuntimeError。错误一定是其他代码没有贴出来! :)
    • 您好,问题来自window = viBadOSUI() 解释器说。我已经注释掉了所有可能的东西,但代码仍然无法运行,抱怨这一点。还有一件事;我不是很喜欢这种方法,也不明白为什么要使用它,因为如果我想在我的 viUtils.py 文件中使用多个函数,我不能这样调用它们,而且似乎非常混乱,真的必须有一个正确的方法来做到这一点[?] 不是说我不感谢你的帮助,我愿意,但这种方式感觉不对。
    • 如果您发布了我可以运行以重现错误的代码,我会看一下——不过我不能保证我能找到它。关于您更大的问题(为什么使用这种方法):您能否详细说明为什么“如果我想在我的 viUtils.py 文件中使用多个函数,我不能以这种方式调用所有函数”?能举个例子吗?
    • 我目前无法使用代码访问硬盘,但要回答第二部分,如果我想让每个窗口都可拖动,或者在屏幕上居中,我没有想在整个应用程序中复制粘贴该代码,太乱了,我想要一个包含重复使用的方法的 viUtils.py 文件,并在需要时调用该文件。一个更具体的例子是我可能需要使用该方法使窗口居中,使其可拖动,并且可能我所有的窗口上都有一个倒数计时器,关键是如果此方法不让我访问我自己的功能我需要不止一个。
    【解决方案2】:

    方法上的self(第一个)参数指的是绑定它的实例。方法外的self.moving = False 等价物是将False 绑定到实例的moving 属性,例如obj.moving = False.

    【讨论】:

    • 不要粗鲁,但你几乎没有提供答案就改写了我的问题。如果您有解决方案,我很乐意倾听:)
    猜你喜欢
    • 2016-07-13
    • 2022-12-19
    • 1970-01-01
    • 2018-08-18
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多