【问题标题】:PyQt4 scrollbar interacts incorrectly with embedded scenesPyQt4 滚动条与嵌入式场景交互不正确
【发布时间】:2018-04-05 19:12:14
【问题描述】:

我在将 PyQt4 滚动条(在 MainWindow 上)与嵌入场景结合起来时遇到问题 - 在我调整窗口大小之前一切正常,之后我的场景开始随着滚动条离开页面而移动。

以下是说明此行为的简化的完整代码(随后附上两个屏幕截图以明确展示此交互):

import sys, os
from pyface.qt import QtGui, QtCore
os.environ['ETS_TOOLKIT'] = 'qt4'

from traits.api import HasTraits,Instance,on_trait_change
from traitsui.api import View,Item
from mayavi import mlab
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, SceneEditor

class Mayavi_Scene(HasTraits):
    scene = Instance(MlabSceneModel, ())

    @on_trait_change('scene.activated')
    def update_scene(self):
        Mayavi_Scene.fig1 = mlab.figure(1, bgcolor=(.5,.5,.5))
        self.scene.mlab.clf(figure=Mayavi_Scene.fig1)
        testPlot = mlab.test_contour3d()

    view = View(Item('scene', editor = SceneEditor(scene_class=MayaviScene),
                    height=300, width=300, show_label=False),
                resizable=True,
                )

class P1(QtGui.QWidget):
    def __init__(self, parent=None):
        super(P1, self).__init__(parent)
        layout = QtGui.QGridLayout(self)
        layout.setContentsMargins(20,20,20,20)
        layout.setSpacing(10)

        self.label_edge1 = QtGui.QLabel('')
        self.label_edge1.setMargin(5)
        self.label_edge1.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken)
        layout.addWidget(self.label_edge1, 0, 0, 10, 10)
        self.label_edge1.show()

        self.label_avgVol = QtGui.QLabel('Test')
        self.label_avgVol.setMargin(5)
        self.label_avgVol.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken)
        self.label_avgVol.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter)
        layout.addWidget(self.label_avgVol, 0, 0, 1, 10)
        self.label_avgVol.show()

        self.viz1 = Mayavi_Scene()
        self.ui1 = self.viz1.edit_traits(parent=self, kind='subpanel').control
        layout.addWidget(self.ui1, 1, 1, 1, 9)

class P2(QtGui.QWidget):    
    def __init__(self, parent=None):
        super(P2, self).__init__(parent)
        layout = QtGui.QGridLayout(self)
        layout.setContentsMargins(20,20,20,20)
        layout.setSpacing(10)

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setGeometry(50, 50, 500, 500)   

        tab1 = P1(self)
        tab2 = P2(self)

        self.tabs = QtGui.QTabWidget(self)
        self.tabs.resize(250,150)

        self.tabs.addTab(tab1, 'Page 1')
        self.tabs.addTab(tab2, 'Page 2')

        self.setWindowTitle('SCROLLBAR ERROR EXAMPLE')

        self.groupscroll = QtGui.QHBoxLayout()
        self.groupscrollbox = QtGui.QGroupBox()

        self.MVB = QtGui.QVBoxLayout()
        self.MVB.addWidget(self.tabs)

        scroll = QtGui.QScrollArea()
        widget = QtGui.QWidget(self)
        widget.setLayout(QtGui.QHBoxLayout())
        widget.layout().addWidget(self.groupscrollbox)
        scroll.setWidget(widget)
        scroll.setWidgetResizable(True)
        self.groupscrollbox.setLayout(self.MVB)
        self.groupscroll.addWidget(scroll)
        self.setCentralWidget(scroll)
        self.show()

if __name__ == '__main__':
    app = QtGui.QApplication.instance()
    w = MainWindow()
    sys.exit(app.exec_())

重构之前

重构后

编辑: .gif 以显示效果(注意对象如何被包含在末尾的自己的框架所覆盖,而不是随之移动;这就像没有通知 3d 场景对象周围的一切都在改变):

【问题讨论】:

  • 我对这段代码没有任何问题。你能在问题发生时更好地解释一下吗?
  • @ymmx 当我将鼠标放在 GUI 窗口最底部的外部框架上,然后继续向上拖动窗口(从下方将其最小化)时,会出现问题。当窗口最小化超过场景所在的位置时,而不是像其他所有内容一样覆盖在下面的场景,它实际上开始向上移动并离开屏幕(在 GUI 内部窗口框架下方),如图 2 所示。同样可以滚动时从左到右发生。

标签: python pyqt pyqt4 scrollbar mayavi


【解决方案1】:

我修改了添加滚动条的地方。

import sys, os
from pyface.qt import QtGui, QtCore
os.environ['ETS_TOOLKIT'] = 'qt4'

from traits.api import HasTraits,Instance,on_trait_change
from traitsui.api import View,Item
from mayavi import mlab
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, SceneEditor

class Mayavi_Scene(HasTraits):
    scene = Instance(MlabSceneModel, ())

    @on_trait_change('scene.activated')
    def update_scene(self):
        Mayavi_Scene.fig1 = mlab.figure(1, bgcolor=(.5,.5,.5))
        self.scene.mlab.clf(figure=Mayavi_Scene.fig1)
        testPlot = mlab.test_contour3d()

    view = View(Item('scene', editor = SceneEditor(scene_class=MayaviScene),
                    height=300, width=300, show_label=False),
                resizable=True,
                )

class P1(QtGui.QWidget):
    def __init__(self, parent=None):
        super(P1, self).__init__(parent)
        layout = QtGui.QGridLayout(self)
        layout.setContentsMargins(20,20,20,20)
        layout.setSpacing(10)

        self.label_edge1 = QtGui.QLabel('')
        self.label_edge1.setMargin(5)
        self.label_edge1.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken)
        layout.addWidget(self.label_edge1, 0, 0, 10, 10)
        self.label_edge1.show()

        self.label_avgVol = QtGui.QLabel('Test')
        self.label_avgVol.setMargin(5)
        self.label_avgVol.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken)
        self.label_avgVol.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter)
        layout.addWidget(self.label_avgVol, 0, 0, 1, 10)
        self.label_avgVol.show()



        self.groupscroll = QtGui.QHBoxLayout()
        self.groupscrollbox = QtGui.QGroupBox()



        self.viz1 = Mayavi_Scene()
        self.ui1 = self.viz1.edit_traits(parent=self, kind='subpanel').control

        self.MVB = QtGui.QVBoxLayout()
        self.MVB.addWidget(self.ui1)

        scroll = QtGui.QScrollArea()
        widget = QtGui.QWidget(self)
        widget.setLayout(QtGui.QHBoxLayout())
        widget.layout().addWidget(self.groupscrollbox)
        scroll.setWidget(widget)
        scroll.setWidgetResizable(True)
        self.groupscrollbox.setLayout(self.MVB)
        self.groupscroll.addWidget(scroll)



        layout.addWidget(scroll, 1, 1, 1, 9)



class P2(QtGui.QWidget):    
    def __init__(self, parent=None):
        super(P2, self).__init__(parent)
        layout = QtGui.QGridLayout(self)
        layout.setContentsMargins(20,20,20,20)
        layout.setSpacing(10)

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setGeometry(50, 50, 500, 500)   

        tab1 = P1(self)
        tab2 = P2(self)

        self.tabs = QtGui.QTabWidget(self)
        self.tabs.resize(250,150)

        self.tabs.addTab(tab1, 'Page 1')
        self.tabs.addTab(tab2, 'Page 2')

        self.setWindowTitle('SCROLLBAR ERROR EXAMPLE')


        self.setCentralWidget(self.tabs)
        self.show()

if __name__ == '__main__':
    app = QtGui.QApplication.instance()
    w = MainWindow()
    sys.exit(app.exec_())

在这种情况下,滚动条位于选项卡内部而不是外部。然后你会得到类似的东西:

但我不确定这是否是您想要的。

【讨论】:

  • 感谢您对此进行测试。您添加的内部滚动条可能是最佳选择。尽管在调整窗口大小时场景向上移动(字面意思是离开框架甚至消失)仍然感觉很奇怪:当您抓住窗口的底部并将其从初始垂直高度向上拖动到垂直高度 = 0 时。你看到的和我一样吗?所有其他小部件保持原位。
  • 另外,尝试使用屏幕截图中设置的框架左右滚动。这里甚至发生了一些奇怪的事情,场景标签随着滚动条的拖动而左右移动,但实际的场景对象停留在中间(如果拖得太远,最终会被框架覆盖)。
  • 我想我没有这个问题。你能提供一个带有一些帧的 GIF 来说明发生了什么吗?
  • 感谢您一直支持我!我在初始帖子中上传了一个 .gif 作为编辑
  • 我根本没有这种行为......我也看不出它在代码中的来源。
猜你喜欢
  • 2022-01-24
  • 1970-01-01
  • 1970-01-01
  • 2022-11-01
  • 2019-02-12
  • 1970-01-01
  • 2017-06-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多