如何创建拆分器网格
How to create a grid of splitters
我想做的是将拆分器添加到 QGridLayout 以便使用鼠标调整布局大小。因此,例如:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
self.grid = QGridLayout()
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
self.grid.addWidget(l_a, 0, 0)
self.grid.addWidget(l_b, 0, 1)
self.grid.addWidget(l_c, 0, 2)
self.grid.addWidget(l_d, 1, 0)
self.grid.addWidget(l_e, 1, 1)
self.grid.addWidget(l_f, 1, 2)
self.grid.addWidget(l_g, 2, 0)
self.grid.addWidget(l_h, 2, 1)
self.grid.addWidget(l_i, 2, 2)
self.wid.setLayout(self.grid)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
我明白了:
我想要的不是彩色线,而是可以垂直(对于绿线)和水平(对于红线)单击并拖动网格边界。
我直接用 QSplitter 尝试了一些东西,但我最终得到:
水平拆分没问题,但垂直拆分不再对齐:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
# self.grid = QGridLayout()
self.globallayout = QVBoxLayout()
self.split_V = QSplitter(Qt.Vertical)
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_a)
split_H.addWidget(l_b)
split_H.addWidget(l_c)
self.split_V.addWidget(split_H)
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_d)
split_H.addWidget(l_e)
split_H.addWidget(l_f)
self.split_V.addWidget(split_H)
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_g)
split_H.addWidget(l_h)
split_H.addWidget(l_i)
self.split_V.addWidget(split_H)
self.globallayout.addWidget(self.split_V)
self.wid.setLayout(self.globallayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
更新
我想我几乎找到了一个解决方案,其中使用了一个函数,以便每当更改垂直拆分时,它都会重新对齐它们:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
# self.grid = QGridLayout()
self.globallayout = QVBoxLayout()
self.split_V = QSplitter(Qt.Vertical)
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
self.split_H1 = QSplitter(Qt.Horizontal)
self.split_H1.addWidget(l_a)
self.split_H1.addWidget(l_b)
self.split_H1.addWidget(l_c)
self.split_V.addWidget(self.split_H1)
self.split_H2 = QSplitter(Qt.Horizontal)
self.split_H2.addWidget(l_d)
self.split_H2.addWidget(l_e)
self.split_H2.addWidget(l_f)
self.split_V.addWidget(self.split_H2)
self.split_H3 = QSplitter(Qt.Horizontal)
self.split_H3.addWidget(l_g)
self.split_H3.addWidget(l_h)
self.split_H3.addWidget(l_i)
self.split_V.addWidget(self.split_H3)
self.globallayout.addWidget(self.split_V)
self.wid.setLayout(self.globallayout)
self.split_H1.splitterMoved.connect(self.moveSplitter)
self.split_H2.splitterMoved.connect(self.moveSplitter)
self.split_H3.splitterMoved.connect(self.moveSplitter)
# self.split_H1.splitterMoved
# self.moveSplitter(0,self.split_H1.at )
def moveSplitter( self, index, pos ):
# splt = self._spltA if self.sender() == self._spltB else self._spltB
self.split_H1.blockSignals(True)
self.split_H2.blockSignals(True)
self.split_H3.blockSignals(True)
self.split_H1.moveSplitter(index, pos)
self.split_H2.moveSplitter(index, pos)
self.split_H3.moveSplitter(index, pos)
self.split_H1.blockSignals(False)
self.split_H2.blockSignals(False)
self.split_H3.blockSignals(False)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
但是,一开始我还有一个问题——对齐不正确:
我不知道如何在__init__
中调用函数moveSplitter
看来直接调用moveSplitter
(是受保护的方法)可能会有问题。在 Linux 上使用 Qt-5.10.1 和 PyQt-5.10.1,我发现在 __init__
期间调用时它通常会导致核心转储。 Qt 提供 setSizes
作为 public 方法来改变分离器的位置可能是有充分理由的,因此比 moveSplitter
.
更喜欢它可能是明智的
考虑到这一点,我得出了以下实现:
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
...
self.split_H1.splitterMoved.connect(self.moveSplitter)
self.split_H2.splitterMoved.connect(self.moveSplitter)
self.split_H3.splitterMoved.connect(self.moveSplitter)
QTimer.singleShot(0, lambda: self.split_H1.splitterMoved.emit(0, 0))
def moveSplitter(self, index, pos):
sizes = self.sender().sizes()
for index in range(self.split_V.count()):
self.split_V.widget(index).setSizes(sizes)
single-shot 计时器是必需的,因为在某些平台上 window 的几何图形在显示在屏幕上之前可能未完全初始化。并且注意setSizes
不会触发splitterMoved
,所以使用的时候不需要屏蔽信号
我想做的是将拆分器添加到 QGridLayout 以便使用鼠标调整布局大小。因此,例如:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
self.grid = QGridLayout()
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
self.grid.addWidget(l_a, 0, 0)
self.grid.addWidget(l_b, 0, 1)
self.grid.addWidget(l_c, 0, 2)
self.grid.addWidget(l_d, 1, 0)
self.grid.addWidget(l_e, 1, 1)
self.grid.addWidget(l_f, 1, 2)
self.grid.addWidget(l_g, 2, 0)
self.grid.addWidget(l_h, 2, 1)
self.grid.addWidget(l_i, 2, 2)
self.wid.setLayout(self.grid)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
我明白了:
我想要的不是彩色线,而是可以垂直(对于绿线)和水平(对于红线)单击并拖动网格边界。
我直接用 QSplitter 尝试了一些东西,但我最终得到:
水平拆分没问题,但垂直拆分不再对齐:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
# self.grid = QGridLayout()
self.globallayout = QVBoxLayout()
self.split_V = QSplitter(Qt.Vertical)
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_a)
split_H.addWidget(l_b)
split_H.addWidget(l_c)
self.split_V.addWidget(split_H)
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_d)
split_H.addWidget(l_e)
split_H.addWidget(l_f)
self.split_V.addWidget(split_H)
split_H = QSplitter(Qt.Horizontal)
split_H.addWidget(l_g)
split_H.addWidget(l_h)
split_H.addWidget(l_i)
self.split_V.addWidget(split_H)
self.globallayout.addWidget(self.split_V)
self.wid.setLayout(self.globallayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
更新
我想我几乎找到了一个解决方案,其中使用了一个函数,以便每当更改垂直拆分时,它都会重新对齐它们:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.setFixedWidth(300)
self.setFixedHeight(100)
self.wid = QWidget()
self.setCentralWidget(self.wid)
# self.grid = QGridLayout()
self.globallayout = QVBoxLayout()
self.split_V = QSplitter(Qt.Vertical)
l_a = QLabel('A')
l_b = QLabel('B')
l_c = QLabel('C')
l_d = QLabel('D')
l_e = QLabel('E')
l_f = QLabel('F')
l_g = QLabel('G')
l_h = QLabel('H')
l_i = QLabel('I')
self.split_H1 = QSplitter(Qt.Horizontal)
self.split_H1.addWidget(l_a)
self.split_H1.addWidget(l_b)
self.split_H1.addWidget(l_c)
self.split_V.addWidget(self.split_H1)
self.split_H2 = QSplitter(Qt.Horizontal)
self.split_H2.addWidget(l_d)
self.split_H2.addWidget(l_e)
self.split_H2.addWidget(l_f)
self.split_V.addWidget(self.split_H2)
self.split_H3 = QSplitter(Qt.Horizontal)
self.split_H3.addWidget(l_g)
self.split_H3.addWidget(l_h)
self.split_H3.addWidget(l_i)
self.split_V.addWidget(self.split_H3)
self.globallayout.addWidget(self.split_V)
self.wid.setLayout(self.globallayout)
self.split_H1.splitterMoved.connect(self.moveSplitter)
self.split_H2.splitterMoved.connect(self.moveSplitter)
self.split_H3.splitterMoved.connect(self.moveSplitter)
# self.split_H1.splitterMoved
# self.moveSplitter(0,self.split_H1.at )
def moveSplitter( self, index, pos ):
# splt = self._spltA if self.sender() == self._spltB else self._spltB
self.split_H1.blockSignals(True)
self.split_H2.blockSignals(True)
self.split_H3.blockSignals(True)
self.split_H1.moveSplitter(index, pos)
self.split_H2.moveSplitter(index, pos)
self.split_H3.moveSplitter(index, pos)
self.split_H1.blockSignals(False)
self.split_H2.blockSignals(False)
self.split_H3.blockSignals(False)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
但是,一开始我还有一个问题——对齐不正确:
我不知道如何在__init__
moveSplitter
看来直接调用moveSplitter
(是受保护的方法)可能会有问题。在 Linux 上使用 Qt-5.10.1 和 PyQt-5.10.1,我发现在 __init__
期间调用时它通常会导致核心转储。 Qt 提供 setSizes
作为 public 方法来改变分离器的位置可能是有充分理由的,因此比 moveSplitter
.
考虑到这一点,我得出了以下实现:
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
...
self.split_H1.splitterMoved.connect(self.moveSplitter)
self.split_H2.splitterMoved.connect(self.moveSplitter)
self.split_H3.splitterMoved.connect(self.moveSplitter)
QTimer.singleShot(0, lambda: self.split_H1.splitterMoved.emit(0, 0))
def moveSplitter(self, index, pos):
sizes = self.sender().sizes()
for index in range(self.split_V.count()):
self.split_V.widget(index).setSizes(sizes)
single-shot 计时器是必需的,因为在某些平台上 window 的几何图形在显示在屏幕上之前可能未完全初始化。并且注意setSizes
不会触发splitterMoved
,所以使用的时候不需要屏蔽信号