问题
I'm working on an image viewer with a toolbar on the left. As I have many measures to make but want to use most of the display for the picture and keep the toolbar thin, I would like to use combo_box1
and combo_box2
to select the different widgets displayed in the toolbar.
Example 1: if I choose measurements set 1
in combo_box1
I would then be able to choose between measurements P1-P2
and P3-P4
in combo_box2
.
Example 2: if I choose measurements set 2
in combo_box1
I would then be able to choose between measurements P5-P6
and P7-P8
in combo_box2
.
Here is the code:
from PySide2.QtWidgets import (QWidget, QApplication, QGraphicsView, QGridLayout)
from PySide2 import QtCore, QtWidgets, QtGui
from PySide2.QtOpenGL import *
from PySide2.QtCore import *
from PySide2.QtGui import *
image_path_str='image.jpg'
class View(QGraphicsView):
photo_clicked = QtCore.Signal(QtCore.QPoint)
def __init__(self, parent):
super(View, self).__init__()
self.scene = QtWidgets.QGraphicsScene(self)
self.photo = QtWidgets.QGraphicsPixmapItem()
self.scene.addItem(self.photo)
self.pixmap = QtGui.QPixmap(image_path_str)
self.photo.setPixmap(self.pixmap)
self.setScene(self.scene)
self.setDragMode(QGraphicsView.ScrollHandDrag)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = View(self)
self.layout_contain_P1_P2 = QtWidgets.QGridLayout()
self.checkbox_P1= QtWidgets.QCheckBox("P1",self)
self.line_edit_P1_x = QtWidgets.QLineEdit(self)
self.line_edit_P1_x.setReadOnly(True)
self.line_edit_P1_y = QtWidgets.QLineEdit(self)
self.line_edit_P1_y.setReadOnly(True)
self.layout_contain_P1_P2.addWidget(self.checkbox_P1, 0, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y = QtWidgets.QGridLayout()
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_x, 1, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_y, 2, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P1_x_y, 0, 1, 1, 1)
self.checkbox_P2 = QtWidgets.QCheckBox("P2",self)
self.line_edit_P2_x = QtWidgets.QLineEdit(self)
self.line_edit_P2_x.setReadOnly(True)
self.line_edit_P2_y = QtWidgets.QLineEdit(self)
self.line_edit_P2_y.setReadOnly(True)
self.layout_contain_P1_P2.addWidget(self.checkbox_P2, 1, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y = QtWidgets.QGridLayout()
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_x, 0, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_y, 1, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P2_x_y, 1, 1, Qt.AlignLeft)
self.combo_box1 = QtWidgets.QComboBox(self)
self.combo_box1.addItem("measurements set 1")
self.combo_box1.addItem("measurements set 1")
self.combo_box2 = QtWidgets.QComboBox(self)
self.combo_box2.addItem("P1-P2")
self.combo_box2.addItem("P3-P4")
self.vertical1= QtWidgets.QVBoxLayout()
self.vertical1.addWidget(self.combo_box1)
self.vertical1.addWidget(self.combo_box2)
self.vertical1.addLayout(self.layout_contain_P1_P2)
self.vertical2= QtWidgets.QVBoxLayout()
self.vertical2.addWidget(self.view)
self.horizontal= QtWidgets.QHBoxLayout()
self.horizontal.addLayout(self.vertical1)
self.horizontal.addLayout(self.vertical2)
self.setLayout(self.horizontal)
self.setWindowTitle("Image viewer")
self.setGeometry(200, 200, 1000, 800)
app = QApplication.instance()
if app is None:
app = QApplication([])
w = Window()
w.show()
w.raise_()
QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))
app.exec_()
回答1:
If you analyze your logic, you can see that the data has the structure of a tree:
root
├── measurements set 1
│ ├── P1-P2
│ └── P3-P4
└── measurements set 2
├── P5-P6
└── P7-P8
So it will be used that QComboBox supports as a source of information to a model, and to establish which sheet shows is used rootModelIndex, in the next part I create a generic example that involves a QComboBox plus that is defined by another level in addition to observe the dependency will use a QTreeView
.
import sys
from PySide2.QtWidgets import *
from PySide2.QtGui import *
class Widget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
play = QVBoxLayout(self)
lay = QHBoxLayout()
self.model = create_model(d)
self.treeView = QTreeView()
play.addLayout(lay)
play.addWidget(self.treeView)
self.treeView.setModel(self.model)
self.treeView.expandAll()
ix = self.model.index(0, 0)
self.combos = []
while self.model.hasChildren(ix):
combo = QComboBox()
combo.setModel(self.model)
lay.addWidget(combo)
combo.setRootModelIndex(ix)
combo.setCurrentIndex(0)
ix = ix.child(0, 0)
combo.currentIndexChanged.connect(self.on_currentIndexChanged)
self.combos.append(combo)
def next_combo(self, combo):
ix = self.combos.index(combo)
if ix != len(self.combos)-1:
return self.combos[ix+1]
def on_currentIndexChanged(self, index):
combo = self.sender()
combo_child = self.next_combo(combo)
if combo_child:
p_ix = combo.rootModelIndex()
ix = p_ix.child(index, 0)
combo_child.setRootModelIndex(ix)
combo_child.setCurrentIndex(0)
def load_childrens(values, parent):
for value in values:
name = value["name"]
dependencies = value["dependencies"]
item = QStandardItem(name)
parent.appendRow(item)
load_childrens(dependencies, item)
def create_model(info):
model = QStandardItemModel()
root = QStandardItem("root")
model.appendRow(root)
load_childrens(info, root)
return model
d = [{
'name': 'measurements set 1',
'dependencies': [
{
'name': 'P1-P2',
'dependencies': [
{
'name': "T1",
"dependencies" : []
},
{
'name': "T2",
"dependencies" : []
}
]
},
{
'name': 'P3-P4',
'dependencies': [
{
'name': "T3",
"dependencies" : []
},
{
'name': "T4",
"dependencies" : []
}
]
}
],
},
{
'name': 'measurements set 2',
'dependencies': [
{
'name': 'P5-P6',
'dependencies': [
{
'name': "T5",
"dependencies" : []
},
{
'name': "T6",
"dependencies" : []
}
]
},
{
'name': 'P7-P8',
'dependencies': [
{
'name': "T7",
"dependencies" : []
},
{
'name': "T8",
"dependencies" : []
}
]
}
],
}]
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
In your case, the code is the following:
from PySide2.QtWidgets import QWidget, QApplication, QGraphicsView, QGridLayout, QComboBox, \
QGraphicsScene, QGraphicsPixmapItem, QCheckBox, QLineEdit, QVBoxLayout, QHBoxLayout
from PySide2.QtCore import Signal, QPoint, Qt
from PySide2.QtGui import QPixmap, QStandardItemModel, QStandardItem, QCursor
image_path_str='image.jpg'
class View(QGraphicsView):
photo_clicked = Signal(QPoint)
def __init__(self, parent):
super(View, self).__init__()
self.scene = QGraphicsScene(self)
self.photo = QGraphicsPixmapItem()
self.scene.addItem(self.photo)
self.pixmap = QPixmap(image_path_str)
self.photo.setPixmap(self.pixmap)
self.setScene(self.scene)
self.setDragMode(QGraphicsView.ScrollHandDrag)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = View(self)
self.layout_contain_P1_P2 = QGridLayout()
self.checkbox_P1= QCheckBox("P1",self)
self.line_edit_P1_x = QLineEdit(self)
self.line_edit_P1_x.setReadOnly(True)
self.line_edit_P1_y = QLineEdit(self)
self.line_edit_P1_y.setReadOnly(True)
self.layout_contain_P1_P2.addWidget(self.checkbox_P1, 0, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y = QGridLayout()
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_x, 1, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_y, 2, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P1_x_y, 0, 1, 1, 1)
self.checkbox_P2 = QCheckBox("P2",self)
self.line_edit_P2_x = QLineEdit(self)
self.line_edit_P2_x.setReadOnly(True)
self.line_edit_P2_y = QLineEdit(self)
self.line_edit_P2_y.setReadOnly(True)
self.layout_contain_P1_P2.addWidget(self.checkbox_P2, 1, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y = QGridLayout()
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_x, 0, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_y, 1, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P2_x_y, 1, 1, Qt.AlignLeft)
self.vertical1= QVBoxLayout()
self.model = create_model(d)
ix = self.model.index(0, 0)
self.combos = []
while self.model.hasChildren(ix):
combo = QComboBox()
combo.setModel(self.model)
self.vertical1.addWidget(combo)
combo.setRootModelIndex(ix)
combo.setCurrentIndex(0)
ix = ix.child(0, 0)
combo.currentIndexChanged.connect(self.on_currentIndexChanged)
self.combos.append(combo)
self.vertical1.addLayout(self.layout_contain_P1_P2)
self.vertical2= QVBoxLayout()
self.vertical2.addWidget(self.view)
self.horizontal= QHBoxLayout()
self.horizontal.addLayout(self.vertical1)
self.horizontal.addLayout(self.vertical2)
self.setLayout(self.horizontal)
self.setWindowTitle("Image viewer")
self.setGeometry(200, 200, 1000, 800)
def next_combo(self, combo):
ix = self.combos.index(combo)
if ix != len(self.combos)-1:
return self.combos[ix+1]
def on_currentIndexChanged(self, index):
combo = self.sender()
combo_child = self.next_combo(combo)
if combo_child:
p_ix = combo.rootModelIndex()
ix = p_ix.child(index, 0)
combo_child.setRootModelIndex(ix)
combo_child.setCurrentIndex(0)
def load_childrens(values, parent):
for value in values:
name = value["name"]
dependencies = value["dependencies"]
item = QStandardItem(name)
parent.appendRow(item)
load_childrens(dependencies, item)
def create_model(info):
model = QStandardItemModel()
root = QStandardItem("root")
model.appendRow(root)
load_childrens(info, root)
return model
d = [{
'name': 'measurements set 1',
'dependencies': [
{
'name': 'P1-P2',
'dependencies': []
},
{
'name': 'P3-P4',
'dependencies': []
}
],
},
{
'name': 'measurements set 2',
'dependencies': [
{
'name': 'P5-P6',
'dependencies': []
},
{
'name': 'P7-P8',
'dependencies': []
}
],
}]
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Window()
w.show()
app.setOverrideCursor(QCursor(Qt.CrossCursor))
sys.exit(app.exec_())
来源:https://stackoverflow.com/questions/50430449/using-qcombobox-to-select-different-set-of-widgets-displayed-in-pyqt5-pyside2