保存 Qtreewidget 项目并通过选择恢复它
Save Qtreewidget item and restore it with selection
我的小软件 Qwidget 和 QTreeWidgets 需要支持。见下图。
这就是我的 Qwidget 的样子。我想在关闭 window 时恢复 Qtreewidget 项目和小部件,并用以前的 selection 恢复它。正如你在下面的脚本中看到的图 below.As 上标记的那样,我使用了 Qsettings,我尝试用 pickle 修复它但不起作用。
编码方面的任何改进都是受欢迎的。
from PyQt5 import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import*
from PyQt5.QtGui import *
import sys
import pickle
iconroot = QFileInfo(__file__).absolutePath()
ORGANIZATION_NAME = 'Circularcolumn App'
ORGANIZATION_DOMAIN = 'Circular shape'
APPLICATION_NAME = 'QSettings program'
SETTINGS_TRAY = 'settings/tray'
class usedcircularshape(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Frequently used shape")
self.setWindowIcon(QIcon(iconroot+"/images/circularcolumnnorebar.png"))
#self.setStyleSheet("background-color:#f2f2f2")
self.addbutton = QPushButton("Add")
self.addbutton.clicked.connect(self.add)
self.deletebutton = QPushButton("Delete")
self.deletebutton.clicked.connect(self.delete)
self.okbutton = QPushButton("Ok")
self.okbutton.setCursor(Qt.PointingHandCursor)
#self.okbutton.clicked.connect(self.hidethiswindow)
self.okbutton.clicked.connect(self.savesetting)
self.cancelbutton = QPushButton("Cancel")
self.cancelbutton.setCursor(Qt.PointingHandCursor)
self.cancelbutton.clicked.connect(self.loadsetting)
#self.cancelbutton.clicked.connect(self.close)
self.addimage()
self.qlabeltodefinesection()
self.treewidget()
self.sectionnamecircular = QLabel('Section name: ')
self.sectionnamecircularindata = QLineEdit('Define en name to section')
self.sectionnamecircularindata.setObjectName("sectionnamecircularindata")
self.sectionnamecircular.setBuddy(self.sectionnamecircularindata)
self.sectionnamecircular.setFocus()
self.grid_sectionname = QHBoxLayout()
self.grid_sectionname.addWidget(self.sectionnamecircular)
self.grid_sectionname.addWidget(self.sectionnamecircularindata)
self.boxlayout = QGridLayout()
self.boxlayout.addLayout(self.grid_sectionname,0,0,1,2)
self.boxlayout.addWidget(self.treewidget,1,0,5,2)
self.boxlayout.addWidget(self.addbutton,2,2)
self.boxlayout.addWidget(self.deletebutton,3,2)
self.boxlayout.addWidget(self.imagelabel,6,0)
self.boxlayout.addLayout(self.qlabelhboxgrid ,6,1)
self.boxlayout.addWidget(self.okbutton,8,1)
self.boxlayout.addWidget(self.cancelbutton,8,2)
self.setLayout(self.boxlayout)
try:
self.loadsetting()
except ( ValueError, TypeError):
pass
def treewidget(self):
self.treewidget = QTreeWidget(self)
self.treewidget.setColumnCount(1)
self.treewidget.setColumnWidth(1,20)
self.treewidget.setHeaderItem(QTreeWidgetItem(['Standard Section Library']))
#self.treewidget.addTopLevelItem(QTreeWidgetItem(['Standard Sectiontype']))
self.treewidget.setRootIsDecorated(True)
self.firstparentitem = QTreeWidgetItem(self.treewidget)
self.firstparentitem.setText(0,'Circular shapes')
self.firstparentitem.setIcon(0,QIcon(iconroot+"/images/circularcolumnnorebar.png"))
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500","D550","D600","D650"
,"D700","D750","D800","D850","D900","D950","D1000"]
for i in standardsectionlist:
self.firstparentitem.addChild(QTreeWidgetItem(["%s"%i]))
self.secondparentitem = QTreeWidgetItem(self.treewidget)
self.secondparentitem.setText(0,'Customized')
self.secondparentitem.setIcon(0,QIcon(iconroot+"/images/circularcolumnnorebar.png"))
self.secondchilditem = QTreeWidgetItem(["D235"])
self.secondparentitem.insertChild(0,self.secondchilditem)
self.secondchilditem.setChildIndicatorPolicy(QTreeWidgetItem.DontShowIndicator)
self.treewidget.move(15,15)
self.treewidget.setGeometry(15,15,200,600)
self.treewidget.setAlternatingRowColors(True)
self.treewidget.expandItem ( self.firstparentitem )
self.show()
print(self.treewidget.headerItem().text(0))
print(self.treewidget.columnCount())
print(self.treewidget.currentColumn())
print(self.treewidget.indexFromItem(self.firstparentitem).row())
print(self.firstparentitem.childCount())
print(self.firstparentitem.child(1).text(0))
print(self.firstparentitem.text(0))
print(self.treewidget.headerItem().text(0))
print(self.treewidget.topLevelItem(0).text(0))
print(self.firstparentitem.isSelected())
print(self.treewidget.selectedItems())
print(self.secondchilditem.text(1))
branchstyle = '''QTreeWidget {border:none;}
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(images/vline.png) 0;}
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(images/branch-more.png) 0;}
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(images/branch-end.png) 0;}
QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(images/branch-closed.png);}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(images/branch-open.png);}'''
self.treewidget.setStyleSheet(branchstyle)
self.treewidget.itemClicked.connect(self.currentitem)
self.treewidget.currentItemChanged.connect(self.current_item_changed)
#@QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem, QtWidgets.QTreeWidgetItem)
def current_item_changed(self, current, previous):
#print('\ncurrent: {}, \nprevious: {}'.format(current, previous))
print(current.text(0),previous)
def add(self):
text, ok = QInputDialog.getText(self, "Add custom section", "Enter section geometry f.ex as D325 or just 325 in mm: ")
if ok:
self.secondchilditem = QTreeWidgetItem(["%s"% text])
self.secondparentitem.insertChild(0,self.secondchilditem)
self.treewidget.expandItem ( self.secondparentitem )
self.gettext = text
print(self.secondparentitem.child(0), self.gettext)
def delete(self):
self.secondparentitem.takeChild(0)
def currentitem(self):
print(self.treewidget.currentItem().text(0),self.treewidget.selectedItems())
self.itemtext = self.treewidget.currentItem().text(0)
if self.itemtext == self.firstparentitem.text(0) or self.itemtext == self.secondparentitem.text(0):
return None
elif self.itemtext == self.treewidget.topLevelItem(0).text(0):
return None
elif self.itemtext == None:
return None
else:
self.select_circular_section = int(self.itemtext.translate({ord('D'):None}))
print(self.itemtext, self.treewidget.selectedItems, self.select_circular_section)
area = str(format(3.1416/4*(self.select_circular_section)**2,'0.2E'))
inerti = str(format(3.1416/64*pow(self.select_circular_section,4),'0.2E'))
self.qlabelcirculardiameterselected = QLabel('')
qlabelcircularareaselected = QLabel('')
qlabelcircularinertimomentselected = QLabel("")
emptylabel1 = QLabel(' ')
self.qlabelcirculardiameterselected.setText('%s mm '% self.select_circular_section)
qlabelcircularareaselected.setText('{} mm2 ' .format(area))
qlabelcircularinertimomentselected.setText("%s mm4 " %(inerti))
qlabelhboxgridselected = QGridLayout()
qlabelhboxgridselected.addWidget(emptylabel1,0,0)
qlabelhboxgridselected.addWidget(self.qlabelcirculardiameterselected,1,0)
qlabelhboxgridselected.addWidget(qlabelcircularareaselected,2,0)
qlabelhboxgridselected.addWidget(qlabelcircularinertimomentselected,3,0)
qlabelhboxgridselected.addWidget(emptylabel1,4,0,5,0)
return print(self.itemtext, self.treewidget.selectedItems, self.select_circular_section), self.boxlayout.addLayout(qlabelhboxgridselected ,6,2),self.qlabelcirculardiameterselected
def addimage(self):
self.imagelabel = QLabel()
self.circularimage = QPixmap(iconroot+"/images/circularcolumnnorebard.png").scaled(230,230,Qt.KeepAspectRatio)
self.imagelabel.setPixmap(self.circularimage)
self.imagelabel.setGeometry(15,15,15,15)
def hidethiswindow(self):
if self.itemtext == self.firstparentitem.text(0) or self.itemtext == self.secondparentitem.text(0):
QMessageBox.about(self,'Error selection','Please, select a section not a text')
elif self.itemtext == self.treewidget.topLevelItem(0).text(0):
QMessageBox.about(self,'Error selection','Please, select a section not a text')
elif self.itemtext == None:
QMessageBox.about(self,'Error selection','Please, select a section not a text')
else:
self.savesetting()
self.hide()
def qlabeltodefinesection(self):
self.qlabelcirculardiameter = QLabel(' D = ')
self.qlabelcirculararea = QLabel(' A = ')
self.qlabelcircularinertimoment = QLabel(" I = ")
self.emptylabel = QLabel(' ')
self.qlabelhboxgrid = QGridLayout()
self.qlabelhboxgrid.addWidget(self.emptylabel,0,0)
self.qlabelhboxgrid.addWidget(self.qlabelcirculardiameter,1,0)
self.qlabelhboxgrid.addWidget(self.qlabelcirculararea,2,0)
self.qlabelhboxgrid.addWidget(self.qlabelcircularinertimoment,3,0)
self.qlabelhboxgrid.addWidget(self.emptylabel,4,0,5,0)
def savesetting(self):
settings = QSettings(ORGANIZATION_NAME,APPLICATION_NAME)
#settings = QSettings('config.ini',QSettings.IniFormat)
settings.beginGroup('D')
settings.setValue(SETTINGS_TRAY,self.geometry())
settings.setValue("LineEdit",self.sectionnamecircularindata.text())
settings.setValue("Selectitem",self.treewidget.currentItem())
settings.setValue("Label",self.qlabelcirculardiameterselected)
settings.endGroup()
print('Saved', )
#self.hide()
def loadsetting(self):
settings = QSettings(ORGANIZATION_NAME,APPLICATION_NAME)
#settings = QSettings('config.ini',QSettings.IniFormat)
settings.beginGroup('D')
myrect = settings.value(SETTINGS_TRAY)
restorelineEdit = settings.value("LineEdit",'')
restoreselectsection = settings.value("Selectitem",)
restoreqlabel = settings.value("Label",'')
self.setGeometry(myrect)
self.sectionnamecircularindata.setText(restorelineEdit)
self.treewidget.setCurrentItem(restoreselectsection)
settings.endGroup()
if __name__ == "__main__":
QCoreApplication.setApplicationName(ORGANIZATION_NAME)
QCoreApplication.setOrganizationDomain(ORGANIZATION_DOMAIN)
QCoreApplication.setApplicationName(APPLICATION_NAME)
app = QApplication(sys.argv)
subwindow=usedcircularshape()
subwindow.show()
app.exec()
代码的作用是什么?
这是工程软件,针对混凝土柱,其理念是用户应该能够选择标准截面,例如D350,D表示直径,350为混凝土圆形柱的直径,单位mm。
用户可以添加自定义形状的圆柱。并且当用户从 Qtreewidget 中单击并 select 一个部分时,该部分应该保留并且全局可用以供进一步计算,这没有显示给她。这是一个在大型具体软件中定义几何的小部件。
我将在下面进一步解释代码。
首先,我创建 Qdialog 并创建 Qtreewidget,一个用于澄清的图像和基于项目 selection 的 Qlabel。
在 Qtreewidget 中,我首先创建一个父项并给它命名为“Circular shapes”
self.firstparentitem = QTreeWidgetItem(self.treewidget)
self.firstparentitem.setText(0,'Circular shapes')
然后 parentitem 有子项,要定义和添加它们,首先我创建一个包含标准部分的列表
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500","D550","D600","D650"
,"D700","D750","D800","D850","D900","D950","D1000"]
并为将子项添加到父项的条件做。
for i in standardsectionlist:
self.firstparentitem.addChild(QTreeWidgetItem(["%s"%i]))
稍后我定义第二个父项并命名为“自定义”并定义一个列表,然后将列表项作为子项添加到第二个父项。
对于用户应该能够从第二个 parentitem 添加和删除 childitem 我创建了 2 个按钮
self.addbutton = QPushButton("Add")
self.deletebutton = QPushButton("Delete")
Addbutton 具有将子项添加到第二个父项的功能。
Deletebutton 具有从第二个父项中删除第一个子项的功能。
def currentitem(self):
currentitem函数有一个功能,当用户点击selectQtreewidget中的一个item时,它获取currenitem文本并从中删除D字母并将其转换为int,然后将其显示为D = Diameter,
A = 面积等…
def hidethiswindow(self)
hidethiswindow 功能这个引导用户 select 一个项目或取消小部件,以防用户错误地 selected headeritem,错误消息将出现并告诉 select 子项目。是不是很强大!
剩下的代码是显示和Qsettings。希望这能解释代码。
你需要做的是为此保存每个项目的数据我已经创建了 itemToTuple 方法,returns 一个要保存的数据的元组,同时考虑到保存的元组你必须设置这些属性为此,您可以使用 tupleToItem 函数(如果您想添加项目的更多信息,您只需修改这些方法)。但是要保存QTreeWidget的所有项,必须遍历整棵树。为此,使用 returns 项及其子项的数据的 dataFromChild 方法。逆过程,即假设数据必须在所有item中建立,则必须使用dataToChild,它为item及其children建立各自的数据。
此外,我将应用程序分成几个 类 进行排序,如果您想要保存小部件的信息,您必须创建一个名为 writeSettings(...) 的方法,其格式类似于对于我展示的那些,应用程序将调用 closeEvent(...) 方法。同样,您可以创建 readSettings(...) 方法并在其构造函数中调用它。
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
ORGANIZATION_NAME = 'Circularcolumn App'
ORGANIZATION_DOMAIN = 'Circular shape'
APPLICATION_NAME = 'QSettings program'
SETTINGS_TRAY = 'settings/tray'
QSS = """
QTreeWidget{
border:none;
}
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(images/vline.png) 0;
}
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(images/branch-more.png) 0;
}
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(images/branch-end.png) 0;
}
QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(images/branch-closed.png);
}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(images/branch-open.png);
}
"""
class TreeWidget(QtWidgets.QTreeWidget):
currentTextChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(TreeWidget, self).__init__(parent)
self.currentItemChanged.connect(self.onCurrentItemChanged)
self.setHeaderLabel('Standard Section Library')
self.setRootIsDecorated(True)
self.setAlternatingRowColors(True)
self.readSettings()
self.expandAll()
def onCurrentItemChanged(self, current, previous):
if current not in [self.topLevelItem(ix) for ix in range(self.topLevelItemCount())]:
self.currentTextChanged.emit(current.text(0))
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
values = settings.value("items")
if values is None:
self.loadDefault()
else:
TreeWidget.dataToChild(values, self.invisibleRootItem())
self.customized_item = None
for ix in range(self.topLevelItemCount()):
tlevel_item = self.topLevelItem(ix)
if tlevel_item.text(0) == "Customized":
self.customized_item = tlevel_item
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
settings.setValue("items", TreeWidget.dataFromChild(self.invisibleRootItem()))
settings.endGroup()
def loadDefault(self):
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500",
"D550","D600","D650","D700","D750","D800","D850","D900","D950","D1000"]
rootItem = QtWidgets.QTreeWidgetItem(self, ['Circular shapes'])
rootItem.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
for element in standardsectionlist:
rootItem.addChild(QtWidgets.QTreeWidgetItem([element]))
self.customized_item = QtWidgets.QTreeWidgetItem(self, ["Customized"])
self.customized_item.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
@staticmethod
def dataToChild(info, item):
TreeWidget.tupleToItem(info["data"], item)
for val in info["childrens"]:
child = QtWidgets.QTreeWidgetItem()
item.addChild(child)
TreeWidget.dataToChild(val, child)
@staticmethod
def tupleToItem(t, item):
# set values to item
ba, isSelected = t
ds = QtCore.QDataStream(ba)
ds >> item
item.setSelected(isSelected)
@staticmethod
def dataFromChild(item):
l = []
for i in range(item.childCount()):
child = item.child(i)
l.append(TreeWidget.dataFromChild(child))
return {"childrens": l, "data": TreeWidget.itemToTuple(item)}
@staticmethod
def itemToTuple(item):
# return values from item
ba = QtCore.QByteArray()
ds = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
ds << item
return ba, item.isSelected()
class InfoWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(InfoWidget, self).__init__(parent)
hlay = QtWidgets.QHBoxLayout(self)
plabel = QtWidgets.QLabel()
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/circularcolumnnorebard.png"))\
.scaled(230, 230, QtCore.Qt.KeepAspectRatio)
plabel.setPixmap(pixmap)
hlay.addWidget(plabel)
self.ilabel = QtWidgets.QLabel()
hlay.addWidget(self.ilabel)
hlay.addStretch()
self.readSettings()
@QtCore.pyqtSlot(str)
def setData(self, text):
try:
circular_section = int(text.translate({ord('D'): ""}))
area = (3.1416/4)*(circular_section**2)
inertia = (3.1416/64)*circular_section**4
fmt = "D = {}mm\nA = {:0.2E}mm2\n I = {:0.2E}mm4"
self.ilabel.setText(fmt.format(circular_section, area, inertia))
except ValueError:
pass
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
self.ilabel.setText(settings.value("text", ""))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
settings.setValue("text", self.ilabel.text())
settings.endGroup()
class CircularDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(CircularDialog, self).__init__(parent)
grid = QtWidgets.QGridLayout(self)
self.tree = TreeWidget()
self.infoWidget = InfoWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Section name: ")
section_edit = QtWidgets.QLineEdit('Define en name to section')
section_lay.addWidget(section_label)
section_lay.addWidget(section_edit)
self.tree.currentTextChanged.connect(self.infoWidget.setData)
button_layout = QtWidgets.QVBoxLayout()
add_button = QtWidgets.QPushButton("Add")
add_button.clicked.connect(self.addItem)
delete_button = QtWidgets.QPushButton("Delete")
delete_button.clicked.connect(self.removeItem)
button_layout.addWidget(add_button, alignment=QtCore.Qt.AlignBottom)
button_layout.addWidget(delete_button, alignment=QtCore.Qt.AlignTop)
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
# for windows, posible bug
self.accepted.connect(self.write_all_data)
self.rejected.connect(self.write_all_data)
grid.addLayout(section_lay, 0, 0)
grid.addWidget(self.tree, 1, 0)
grid.addLayout(button_layout, 1, 1)
grid.addWidget(self.infoWidget, 2, 0, 1, 2)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.readSettings()
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
self.setGeometry(settings.value("geometry", QtCore.QRect(300, 300, 400, 600)))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
settings.setValue("geometry", self.geometry())
settings.endGroup()
def closeEvent(self, event):
self.write_all_data()
super(CircularDialog, self).closeEvent(event)
def write_all_data(self):
for children in self.findChildren(QtWidgets.QWidget) + [self]:
if hasattr(children, "writeSettings"):
children.writeSettings()
def addItem(self):
text, ok = QtWidgets.QInputDialog.getText(self, "Add custom section",
"Enter section geometry f.ex as D325 or just 325 in mm: ")
if ok:
it = QtWidgets.QTreeWidgetItem([text])
self.tree.customized_item.addChild(it)
def removeItem(self):
it = self.tree.customized_item.takeChild(0)
del it
if __name__ == '__main__':
QtCore.QCoreApplication.setApplicationName(ORGANIZATION_NAME)
QtCore.QCoreApplication.setOrganizationDomain(ORGANIZATION_DOMAIN)
QtCore.QCoreApplication.setApplicationName(APPLICATION_NAME)
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet(QSS)
w = CircularDialog()
w.show()
sys.exit(app.exec_())
我的小软件 Qwidget 和 QTreeWidgets 需要支持。见下图。
这就是我的 Qwidget 的样子。我想在关闭 window 时恢复 Qtreewidget 项目和小部件,并用以前的 selection 恢复它。正如你在下面的脚本中看到的图 below.As 上标记的那样,我使用了 Qsettings,我尝试用 pickle 修复它但不起作用。
编码方面的任何改进都是受欢迎的。
from PyQt5 import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import*
from PyQt5.QtGui import *
import sys
import pickle
iconroot = QFileInfo(__file__).absolutePath()
ORGANIZATION_NAME = 'Circularcolumn App'
ORGANIZATION_DOMAIN = 'Circular shape'
APPLICATION_NAME = 'QSettings program'
SETTINGS_TRAY = 'settings/tray'
class usedcircularshape(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Frequently used shape")
self.setWindowIcon(QIcon(iconroot+"/images/circularcolumnnorebar.png"))
#self.setStyleSheet("background-color:#f2f2f2")
self.addbutton = QPushButton("Add")
self.addbutton.clicked.connect(self.add)
self.deletebutton = QPushButton("Delete")
self.deletebutton.clicked.connect(self.delete)
self.okbutton = QPushButton("Ok")
self.okbutton.setCursor(Qt.PointingHandCursor)
#self.okbutton.clicked.connect(self.hidethiswindow)
self.okbutton.clicked.connect(self.savesetting)
self.cancelbutton = QPushButton("Cancel")
self.cancelbutton.setCursor(Qt.PointingHandCursor)
self.cancelbutton.clicked.connect(self.loadsetting)
#self.cancelbutton.clicked.connect(self.close)
self.addimage()
self.qlabeltodefinesection()
self.treewidget()
self.sectionnamecircular = QLabel('Section name: ')
self.sectionnamecircularindata = QLineEdit('Define en name to section')
self.sectionnamecircularindata.setObjectName("sectionnamecircularindata")
self.sectionnamecircular.setBuddy(self.sectionnamecircularindata)
self.sectionnamecircular.setFocus()
self.grid_sectionname = QHBoxLayout()
self.grid_sectionname.addWidget(self.sectionnamecircular)
self.grid_sectionname.addWidget(self.sectionnamecircularindata)
self.boxlayout = QGridLayout()
self.boxlayout.addLayout(self.grid_sectionname,0,0,1,2)
self.boxlayout.addWidget(self.treewidget,1,0,5,2)
self.boxlayout.addWidget(self.addbutton,2,2)
self.boxlayout.addWidget(self.deletebutton,3,2)
self.boxlayout.addWidget(self.imagelabel,6,0)
self.boxlayout.addLayout(self.qlabelhboxgrid ,6,1)
self.boxlayout.addWidget(self.okbutton,8,1)
self.boxlayout.addWidget(self.cancelbutton,8,2)
self.setLayout(self.boxlayout)
try:
self.loadsetting()
except ( ValueError, TypeError):
pass
def treewidget(self):
self.treewidget = QTreeWidget(self)
self.treewidget.setColumnCount(1)
self.treewidget.setColumnWidth(1,20)
self.treewidget.setHeaderItem(QTreeWidgetItem(['Standard Section Library']))
#self.treewidget.addTopLevelItem(QTreeWidgetItem(['Standard Sectiontype']))
self.treewidget.setRootIsDecorated(True)
self.firstparentitem = QTreeWidgetItem(self.treewidget)
self.firstparentitem.setText(0,'Circular shapes')
self.firstparentitem.setIcon(0,QIcon(iconroot+"/images/circularcolumnnorebar.png"))
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500","D550","D600","D650"
,"D700","D750","D800","D850","D900","D950","D1000"]
for i in standardsectionlist:
self.firstparentitem.addChild(QTreeWidgetItem(["%s"%i]))
self.secondparentitem = QTreeWidgetItem(self.treewidget)
self.secondparentitem.setText(0,'Customized')
self.secondparentitem.setIcon(0,QIcon(iconroot+"/images/circularcolumnnorebar.png"))
self.secondchilditem = QTreeWidgetItem(["D235"])
self.secondparentitem.insertChild(0,self.secondchilditem)
self.secondchilditem.setChildIndicatorPolicy(QTreeWidgetItem.DontShowIndicator)
self.treewidget.move(15,15)
self.treewidget.setGeometry(15,15,200,600)
self.treewidget.setAlternatingRowColors(True)
self.treewidget.expandItem ( self.firstparentitem )
self.show()
print(self.treewidget.headerItem().text(0))
print(self.treewidget.columnCount())
print(self.treewidget.currentColumn())
print(self.treewidget.indexFromItem(self.firstparentitem).row())
print(self.firstparentitem.childCount())
print(self.firstparentitem.child(1).text(0))
print(self.firstparentitem.text(0))
print(self.treewidget.headerItem().text(0))
print(self.treewidget.topLevelItem(0).text(0))
print(self.firstparentitem.isSelected())
print(self.treewidget.selectedItems())
print(self.secondchilditem.text(1))
branchstyle = '''QTreeWidget {border:none;}
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(images/vline.png) 0;}
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(images/branch-more.png) 0;}
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(images/branch-end.png) 0;}
QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(images/branch-closed.png);}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(images/branch-open.png);}'''
self.treewidget.setStyleSheet(branchstyle)
self.treewidget.itemClicked.connect(self.currentitem)
self.treewidget.currentItemChanged.connect(self.current_item_changed)
#@QtCore.pyqtSlot(QtWidgets.QTreeWidgetItem, QtWidgets.QTreeWidgetItem)
def current_item_changed(self, current, previous):
#print('\ncurrent: {}, \nprevious: {}'.format(current, previous))
print(current.text(0),previous)
def add(self):
text, ok = QInputDialog.getText(self, "Add custom section", "Enter section geometry f.ex as D325 or just 325 in mm: ")
if ok:
self.secondchilditem = QTreeWidgetItem(["%s"% text])
self.secondparentitem.insertChild(0,self.secondchilditem)
self.treewidget.expandItem ( self.secondparentitem )
self.gettext = text
print(self.secondparentitem.child(0), self.gettext)
def delete(self):
self.secondparentitem.takeChild(0)
def currentitem(self):
print(self.treewidget.currentItem().text(0),self.treewidget.selectedItems())
self.itemtext = self.treewidget.currentItem().text(0)
if self.itemtext == self.firstparentitem.text(0) or self.itemtext == self.secondparentitem.text(0):
return None
elif self.itemtext == self.treewidget.topLevelItem(0).text(0):
return None
elif self.itemtext == None:
return None
else:
self.select_circular_section = int(self.itemtext.translate({ord('D'):None}))
print(self.itemtext, self.treewidget.selectedItems, self.select_circular_section)
area = str(format(3.1416/4*(self.select_circular_section)**2,'0.2E'))
inerti = str(format(3.1416/64*pow(self.select_circular_section,4),'0.2E'))
self.qlabelcirculardiameterselected = QLabel('')
qlabelcircularareaselected = QLabel('')
qlabelcircularinertimomentselected = QLabel("")
emptylabel1 = QLabel(' ')
self.qlabelcirculardiameterselected.setText('%s mm '% self.select_circular_section)
qlabelcircularareaselected.setText('{} mm2 ' .format(area))
qlabelcircularinertimomentselected.setText("%s mm4 " %(inerti))
qlabelhboxgridselected = QGridLayout()
qlabelhboxgridselected.addWidget(emptylabel1,0,0)
qlabelhboxgridselected.addWidget(self.qlabelcirculardiameterselected,1,0)
qlabelhboxgridselected.addWidget(qlabelcircularareaselected,2,0)
qlabelhboxgridselected.addWidget(qlabelcircularinertimomentselected,3,0)
qlabelhboxgridselected.addWidget(emptylabel1,4,0,5,0)
return print(self.itemtext, self.treewidget.selectedItems, self.select_circular_section), self.boxlayout.addLayout(qlabelhboxgridselected ,6,2),self.qlabelcirculardiameterselected
def addimage(self):
self.imagelabel = QLabel()
self.circularimage = QPixmap(iconroot+"/images/circularcolumnnorebard.png").scaled(230,230,Qt.KeepAspectRatio)
self.imagelabel.setPixmap(self.circularimage)
self.imagelabel.setGeometry(15,15,15,15)
def hidethiswindow(self):
if self.itemtext == self.firstparentitem.text(0) or self.itemtext == self.secondparentitem.text(0):
QMessageBox.about(self,'Error selection','Please, select a section not a text')
elif self.itemtext == self.treewidget.topLevelItem(0).text(0):
QMessageBox.about(self,'Error selection','Please, select a section not a text')
elif self.itemtext == None:
QMessageBox.about(self,'Error selection','Please, select a section not a text')
else:
self.savesetting()
self.hide()
def qlabeltodefinesection(self):
self.qlabelcirculardiameter = QLabel(' D = ')
self.qlabelcirculararea = QLabel(' A = ')
self.qlabelcircularinertimoment = QLabel(" I = ")
self.emptylabel = QLabel(' ')
self.qlabelhboxgrid = QGridLayout()
self.qlabelhboxgrid.addWidget(self.emptylabel,0,0)
self.qlabelhboxgrid.addWidget(self.qlabelcirculardiameter,1,0)
self.qlabelhboxgrid.addWidget(self.qlabelcirculararea,2,0)
self.qlabelhboxgrid.addWidget(self.qlabelcircularinertimoment,3,0)
self.qlabelhboxgrid.addWidget(self.emptylabel,4,0,5,0)
def savesetting(self):
settings = QSettings(ORGANIZATION_NAME,APPLICATION_NAME)
#settings = QSettings('config.ini',QSettings.IniFormat)
settings.beginGroup('D')
settings.setValue(SETTINGS_TRAY,self.geometry())
settings.setValue("LineEdit",self.sectionnamecircularindata.text())
settings.setValue("Selectitem",self.treewidget.currentItem())
settings.setValue("Label",self.qlabelcirculardiameterselected)
settings.endGroup()
print('Saved', )
#self.hide()
def loadsetting(self):
settings = QSettings(ORGANIZATION_NAME,APPLICATION_NAME)
#settings = QSettings('config.ini',QSettings.IniFormat)
settings.beginGroup('D')
myrect = settings.value(SETTINGS_TRAY)
restorelineEdit = settings.value("LineEdit",'')
restoreselectsection = settings.value("Selectitem",)
restoreqlabel = settings.value("Label",'')
self.setGeometry(myrect)
self.sectionnamecircularindata.setText(restorelineEdit)
self.treewidget.setCurrentItem(restoreselectsection)
settings.endGroup()
if __name__ == "__main__":
QCoreApplication.setApplicationName(ORGANIZATION_NAME)
QCoreApplication.setOrganizationDomain(ORGANIZATION_DOMAIN)
QCoreApplication.setApplicationName(APPLICATION_NAME)
app = QApplication(sys.argv)
subwindow=usedcircularshape()
subwindow.show()
app.exec()
代码的作用是什么?
这是工程软件,针对混凝土柱,其理念是用户应该能够选择标准截面,例如D350,D表示直径,350为混凝土圆形柱的直径,单位mm。 用户可以添加自定义形状的圆柱。并且当用户从 Qtreewidget 中单击并 select 一个部分时,该部分应该保留并且全局可用以供进一步计算,这没有显示给她。这是一个在大型具体软件中定义几何的小部件。 我将在下面进一步解释代码。 首先,我创建 Qdialog 并创建 Qtreewidget,一个用于澄清的图像和基于项目 selection 的 Qlabel。 在 Qtreewidget 中,我首先创建一个父项并给它命名为“Circular shapes”
self.firstparentitem = QTreeWidgetItem(self.treewidget)
self.firstparentitem.setText(0,'Circular shapes')
然后 parentitem 有子项,要定义和添加它们,首先我创建一个包含标准部分的列表
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500","D550","D600","D650"
,"D700","D750","D800","D850","D900","D950","D1000"]
并为将子项添加到父项的条件做。
for i in standardsectionlist:
self.firstparentitem.addChild(QTreeWidgetItem(["%s"%i]))
稍后我定义第二个父项并命名为“自定义”并定义一个列表,然后将列表项作为子项添加到第二个父项。 对于用户应该能够从第二个 parentitem 添加和删除 childitem 我创建了 2 个按钮
self.addbutton = QPushButton("Add")
self.deletebutton = QPushButton("Delete")
Addbutton 具有将子项添加到第二个父项的功能。 Deletebutton 具有从第二个父项中删除第一个子项的功能。
def currentitem(self):
currentitem函数有一个功能,当用户点击selectQtreewidget中的一个item时,它获取currenitem文本并从中删除D字母并将其转换为int,然后将其显示为D = Diameter, A = 面积等…
def hidethiswindow(self)
hidethiswindow 功能这个引导用户 select 一个项目或取消小部件,以防用户错误地 selected headeritem,错误消息将出现并告诉 select 子项目。是不是很强大!
剩下的代码是显示和Qsettings。希望这能解释代码。
你需要做的是为此保存每个项目的数据我已经创建了 itemToTuple 方法,returns 一个要保存的数据的元组,同时考虑到保存的元组你必须设置这些属性为此,您可以使用 tupleToItem 函数(如果您想添加项目的更多信息,您只需修改这些方法)。但是要保存QTreeWidget的所有项,必须遍历整棵树。为此,使用 returns 项及其子项的数据的 dataFromChild 方法。逆过程,即假设数据必须在所有item中建立,则必须使用dataToChild,它为item及其children建立各自的数据。
此外,我将应用程序分成几个 类 进行排序,如果您想要保存小部件的信息,您必须创建一个名为 writeSettings(...) 的方法,其格式类似于对于我展示的那些,应用程序将调用 closeEvent(...) 方法。同样,您可以创建 readSettings(...) 方法并在其构造函数中调用它。
import os
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
ORGANIZATION_NAME = 'Circularcolumn App'
ORGANIZATION_DOMAIN = 'Circular shape'
APPLICATION_NAME = 'QSettings program'
SETTINGS_TRAY = 'settings/tray'
QSS = """
QTreeWidget{
border:none;
}
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(images/vline.png) 0;
}
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(images/branch-more.png) 0;
}
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(images/branch-end.png) 0;
}
QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(images/branch-closed.png);
}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(images/branch-open.png);
}
"""
class TreeWidget(QtWidgets.QTreeWidget):
currentTextChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(TreeWidget, self).__init__(parent)
self.currentItemChanged.connect(self.onCurrentItemChanged)
self.setHeaderLabel('Standard Section Library')
self.setRootIsDecorated(True)
self.setAlternatingRowColors(True)
self.readSettings()
self.expandAll()
def onCurrentItemChanged(self, current, previous):
if current not in [self.topLevelItem(ix) for ix in range(self.topLevelItemCount())]:
self.currentTextChanged.emit(current.text(0))
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
values = settings.value("items")
if values is None:
self.loadDefault()
else:
TreeWidget.dataToChild(values, self.invisibleRootItem())
self.customized_item = None
for ix in range(self.topLevelItemCount()):
tlevel_item = self.topLevelItem(ix)
if tlevel_item.text(0) == "Customized":
self.customized_item = tlevel_item
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
settings.setValue("items", TreeWidget.dataFromChild(self.invisibleRootItem()))
settings.endGroup()
def loadDefault(self):
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500",
"D550","D600","D650","D700","D750","D800","D850","D900","D950","D1000"]
rootItem = QtWidgets.QTreeWidgetItem(self, ['Circular shapes'])
rootItem.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
for element in standardsectionlist:
rootItem.addChild(QtWidgets.QTreeWidgetItem([element]))
self.customized_item = QtWidgets.QTreeWidgetItem(self, ["Customized"])
self.customized_item.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
@staticmethod
def dataToChild(info, item):
TreeWidget.tupleToItem(info["data"], item)
for val in info["childrens"]:
child = QtWidgets.QTreeWidgetItem()
item.addChild(child)
TreeWidget.dataToChild(val, child)
@staticmethod
def tupleToItem(t, item):
# set values to item
ba, isSelected = t
ds = QtCore.QDataStream(ba)
ds >> item
item.setSelected(isSelected)
@staticmethod
def dataFromChild(item):
l = []
for i in range(item.childCount()):
child = item.child(i)
l.append(TreeWidget.dataFromChild(child))
return {"childrens": l, "data": TreeWidget.itemToTuple(item)}
@staticmethod
def itemToTuple(item):
# return values from item
ba = QtCore.QByteArray()
ds = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
ds << item
return ba, item.isSelected()
class InfoWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(InfoWidget, self).__init__(parent)
hlay = QtWidgets.QHBoxLayout(self)
plabel = QtWidgets.QLabel()
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/circularcolumnnorebard.png"))\
.scaled(230, 230, QtCore.Qt.KeepAspectRatio)
plabel.setPixmap(pixmap)
hlay.addWidget(plabel)
self.ilabel = QtWidgets.QLabel()
hlay.addWidget(self.ilabel)
hlay.addStretch()
self.readSettings()
@QtCore.pyqtSlot(str)
def setData(self, text):
try:
circular_section = int(text.translate({ord('D'): ""}))
area = (3.1416/4)*(circular_section**2)
inertia = (3.1416/64)*circular_section**4
fmt = "D = {}mm\nA = {:0.2E}mm2\n I = {:0.2E}mm4"
self.ilabel.setText(fmt.format(circular_section, area, inertia))
except ValueError:
pass
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
self.ilabel.setText(settings.value("text", ""))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
settings.setValue("text", self.ilabel.text())
settings.endGroup()
class CircularDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(CircularDialog, self).__init__(parent)
grid = QtWidgets.QGridLayout(self)
self.tree = TreeWidget()
self.infoWidget = InfoWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Section name: ")
section_edit = QtWidgets.QLineEdit('Define en name to section')
section_lay.addWidget(section_label)
section_lay.addWidget(section_edit)
self.tree.currentTextChanged.connect(self.infoWidget.setData)
button_layout = QtWidgets.QVBoxLayout()
add_button = QtWidgets.QPushButton("Add")
add_button.clicked.connect(self.addItem)
delete_button = QtWidgets.QPushButton("Delete")
delete_button.clicked.connect(self.removeItem)
button_layout.addWidget(add_button, alignment=QtCore.Qt.AlignBottom)
button_layout.addWidget(delete_button, alignment=QtCore.Qt.AlignTop)
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
# for windows, posible bug
self.accepted.connect(self.write_all_data)
self.rejected.connect(self.write_all_data)
grid.addLayout(section_lay, 0, 0)
grid.addWidget(self.tree, 1, 0)
grid.addLayout(button_layout, 1, 1)
grid.addWidget(self.infoWidget, 2, 0, 1, 2)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.readSettings()
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
self.setGeometry(settings.value("geometry", QtCore.QRect(300, 300, 400, 600)))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
settings.setValue("geometry", self.geometry())
settings.endGroup()
def closeEvent(self, event):
self.write_all_data()
super(CircularDialog, self).closeEvent(event)
def write_all_data(self):
for children in self.findChildren(QtWidgets.QWidget) + [self]:
if hasattr(children, "writeSettings"):
children.writeSettings()
def addItem(self):
text, ok = QtWidgets.QInputDialog.getText(self, "Add custom section",
"Enter section geometry f.ex as D325 or just 325 in mm: ")
if ok:
it = QtWidgets.QTreeWidgetItem([text])
self.tree.customized_item.addChild(it)
def removeItem(self):
it = self.tree.customized_item.takeChild(0)
del it
if __name__ == '__main__':
QtCore.QCoreApplication.setApplicationName(ORGANIZATION_NAME)
QtCore.QCoreApplication.setOrganizationDomain(ORGANIZATION_DOMAIN)
QtCore.QCoreApplication.setApplicationName(APPLICATION_NAME)
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet(QSS)
w = CircularDialog()
w.show()
sys.exit(app.exec_())