[英]How to drag a xml file and drop it in Qtableview and parse the xml at the same time
I am trying to drag an XML file in QtableView or QtableWidget and parse the file at the same time and display it in different columns in QtableView. 我试图在QtableView或QtableWidget中拖动XML文件并同时解析该文件,并将其显示在QtableView的不同列中。
I have gone through many examples but not sure where to begin with , are there any tutorial or example , I need this to be done in PyQt5. 我已经看过许多示例,但是不确定从哪里开始,是否有任何教程或示例,我需要在PyQt5中完成。
I am doing this for the first time and not sure , how to start this. 我是第一次这样做,不确定如何开始。
one very simple examples of XML file that i have is: each layer name is the first columns and then the subtags are the corresponding properties of the same. 我拥有的XML文件的一个非常简单的示例是:每个图层名称是第一列,然后子标记是相同的相应属性。
<xtech>
<Layer id="0" name="EM_UPKG">
<SourceLayer>NoSource</SourceLayer>
<Color>
<R>255</R>
<G>255</G>
<B>0</B>
</Color>
<Offset>
<value>114.215</value>
<dependent>EM_AlN</dependent>
<placement>Top</placement>
</Offset>
<Thickness>
<value>50</value>
<dependent>-1</dependent>
</Thickness>
<Material>air</Material>
<Port>NO</Port>
<Resistivity>0</Resistivity>
<Transparency>0.8</Transparency>
<Sheet_Priority>0</Sheet_Priority>
</Layer>
<Layer id="1" name="EM_UP">
<SourceLayer>NoSource</SourceLayer>
<Color>
<R>255</R>
<G>128</G>
<B>0</B>
</Color>
<Offset>
<value>164.215</value>
<dependent>EM_UVIA</dependent>
<placement>Top</placement>
</Offset>
<Thickness>
<value>40</value>
<dependent>-1</dependent>
</Thickness>
<Material>copper</Material>
<Port>NO</Port>
<Resistivity>0</Resistivity>
<Transparency>0</Transparency>
<Sheet_Priority>0</Sheet_Priority>
</Layer>
<Layer id="2" name="EM_UVIA">
<SourceLayer>NoSource</SourceLayer>
<Color>
<R>128</R>
<G>128</G>
<B>0</B>
</Color>
<Offset>
<value>114.215</value>
<dependent>EM_AlN</dependent>
<placement>Top</placement>
</Offset>
<Thickness>
<value>50</value>
<dependent>-1</dependent>
</Thickness>
<Material>copper</Material>
<Port>NO</Port>
<Resistivity>0</Resistivity>
<Transparency>0</Transparency>
<Sheet_Priority>0</Sheet_Priority>
</Layer>
<Layer id="3" name="EM_PKG">
<SourceLayer>NoSource</SourceLayer>
<Color>
<R>255</R>
<G>255</G>
<B>0</B>
</Color>
<Offset>
<value>114.215</value>
<dependent>EM_AlN</dependent>
<placement>Top</placement>
</Offset>
<Thickness>
<value>20</value>
<dependent>-1</dependent>
</Thickness>
<Material>air</Material>
<Port>NO</Port>
<Resistivity>0</Resistivity>
<Transparency>0.8</Transparency>
<Sheet_Priority>0</Sheet_Priority>
</Layer>
<Layer id="4" name="EM_PL">
<SourceLayer>NoSource</SourceLayer>
<Color>
<R>255</R>
<G>128</G>
<B>0</B>
</Color>
<Offset>
<value>114.215</value>
<dependent>EM_AlN</dependent>
<placement>Top</placement>
</Offset>
<Thickness>
<value>95</value>
<dependent>-1</dependent>
</Thickness>
<Material>copper</Material>
<Port>NO</Port>
<Resistivity>0</Resistivity>
<Transparency>0</Transparency>
<Sheet_Priority>0</Sheet_Priority>
</Layer>
<Mesh_Operations>
<Model_Resolution>60</Model_Resolution>
<Surface_Approximation>0.5</Surface_Approximation>
</Mesh_Operations>
<Port_Processing>
<Use_Delta>True</Use_Delta>
<hport_delta>5</hport_delta>
</Port_Processing>
</xtech>
columns should be displayed as: 列应显示为:
TargetLayer, Color, Offset, Thickness, MAterial, Port, Sheet Resistivity, Transparency, Priority and Source Layer TargetLayer,颜色,偏移,厚度,材料,端口,薄层电阻率,透明度,优先级和源图层
So i wrote the code below to implement drag and drop , now i have to look into how to parse the XML file. 因此,我在下面编写了实现拖放的代码,现在我必须研究如何解析XML文件。
def __init__(self,parent=None):
super().__init__()
self.ui = Ui_MainWindowEtechEditor()
self.ui.setupUi(self)
self.setAcceptDrops(True)
self.ui.pushButton.clicked.connect(self.opecolorEditor)
def opecolorEditor(self):
color = QColorDialog(self)
color.setSizeGripEnabled(True)
color.layout().setSizeConstraint(QLayout.SetNoConstraint)
color.show()
def dragEnterEvent(self, e):
if e.mimeData().hasUrls:
e.accept()
else:
e.ignore()
def dragMoveEvent(self, e):
if e.mimeData().hasUrls:
e.accept()
else:
e.ignore()
def dropEvent(self, e, event=None):
if e.mimeData().hasUrls():
e.setDropAction(QtCore.Qt.CopyAction)
e.accept()
drop_list = []
for url in e.mimeData().urls():
fName = (str(url.toLocalFile()))
print("path ", fName)
self.loadExtechfile(fName)
else:
e.ignore()
Qt provides QXmlStreamReader , an Xml parser. Qt提供了XXml解析器QXmlStreamReader 。
The parser reads one element at a time, keeping the current element type and contents, so the only problem is to understand how to keep track of nested elements, as long as the source is well formed. 解析器一次读取一个元素,并保留当前元素的类型和内容,因此唯一的问题是,只要源格式正确,就应该了解如何跟踪嵌套元素。
readNext()
returns the element type ("token") of the xml element (which is accessible through tokenType()
also). readNext()
返回xml元素的元素类型(“令牌”)(也可以通过tokenType()
访问)。
The most important token types are StartElement
and EndElement
, you can use QXmlStreamReader.attributes().value(attrName)
to read the attributes of a StartElement, and xml.readElementText()
for its contents, which might be its text contents or even the raw text of child elements as long as QXmlStreamReader.IncludeChildElements
is provided as last argument. 最重要的标记类型是StartElement
和EndElement
,您可以使用QXmlStreamReader.attributes().value(attrName)
读取StartElement的属性,并使用xml.readElementText()
获取其内容,该内容可能是其文本内容,甚至可能是只要最后一个参数提供QXmlStreamReader.IncludeChildElements
,子元素的原始文本。
Columns = ('Target Layer', 'Color', 'Offset', 'Thickness', 'Material',
'Port', 'Resistivity', 'Transparency', 'Sheet_Priority', 'SourceLayer')
SimpleFields = ('SourceLayer', 'Material', 'Resistivity', 'Port',
'Transparency', 'Sheet_Priority')
class Table(QtWidgets.QTableView):
def __init__(self, *args, **kwargs):
QtWidgets.QTableView.__init__(self, *args, **kwargs)
self.setAcceptDrops(True)
model = QtGui.QStandardItemModel(0, len(Columns))
model.setHorizontalHeaderLabels(Columns)
self.setModel(model)
def dragEnterEvent(self, e):
# be careful, as you forgot the parenthesis of hasUrls()!
if e.mimeData().hasUrls() and any(u.isLocalFile() for u in e.mimeData().urls()):
e.accept()
else:
e.ignore()
# ...
def dropEvent(self, e):
f = QtCore.QFile(e.mimeData().urls()[0].toLocalFile())
if not f.open(f.ReadOnly):
return
xml = QtCore.QXmlStreamReader(f)
valid = False
currentLayer = None
while not xml.atEnd():
if xml.readNext() == xml.StartElement:
# track the first start element and ensure that it's of
# the right type, otherwise ignore the file
if not valid:
if xml.name() != 'xtech':
break
valid = True
continue
if xml.name() == 'Layer':
# if a currentLayer exists, we assume it's finished,
# so we can process it and add its items
if currentLayer:
self.addLayer(currentLayer)
currentLayer = {'Target Layer': xml.attributes().value('name')}
elif xml.name() in SimpleFields:
currentLayer[xml.name()] = xml.readElementText()
elif xml.name() == 'Color':
currentLayer['Color'] = color = QtGui.QColor()
# this is a "nested" field, read its contents until
# it's reached the end element;
while xml.readNext():
if xml.tokenType() == xml.EndElement and xml.name() == 'Color':
break
elif xml.name() == 'R':
color.setRed(int(xml.readElementText()))
elif xml.name() == 'G':
color.setGreen(int(xml.readElementText()))
elif xml.name() == 'B':
color.setBlue(int(xml.readElementText()))
# use the same logic for all other nested fields.
f.close()
def addLayer(self, layer):
# create an empty "row" that can be filled with items in the correct
# order, and that will leave empty cells if some fields do not exist
row = [None] * len(Columns)
for field, value in layer.items():
item = QtGui.QStandardItem()
if isinstance(value, QtGui.QColor):
item.setBackground(value)
else:
item.setData(value, QtCore.Qt.DisplayRole)
row[Columns.index(field)] = item
self.model().appendRow(row)
Some care is necessary about letter cases when parsing elements, you should probably use xml.name().lower()
for comparisons against field names. 解析元素时,对于字母大小写需要xml.name().lower()
,您可能应该使用xml.name().lower()
与字段名称进行比较。
After struglling for few hours i found another parser xml.etree.ElementTree and implemented the parser code like below which works like a charm. 挣扎了几个小时后,我找到了另一个解析器xml.etree.ElementTree并实现了如下的解析器代码,它的工作原理像一个魅力。
def loadExtechfile(self,fName):
print("load file from ", fName)
tree = ET.parse(fName)
root = tree.getroot()
for layer in root.findall('Layer'):
layerName =layer.get('name')
sourceLayer = layer.find('SourceLayer').text
for color in layer.findall('Color'):
r = color.find('R').text
g = color.find('G').text
b = color.find('B').text
combinedRGB = r+","+g+","+b
for offset in layer.findall('Offset'):
value = offset.find('value').text
dep = offset.find('dependent').text
plc = offset.find('placement').text
if dep == "-1" and plc == "None":
combinedOffset = value
else:
combinedOffset = value + "(= " + dep + " [" + plc + "])"
for thickness in layer.findall('Thickness'):
valueT = thickness.find('value').text
depT = thickness.find('dependent').text
if depT != "-1":
combinedThickness = valueT + "(=" + depT + ")"
else:
combinedThickness = valueT
material = layer.find('Material').text
port = layer.find('Port').text
res = layer.find('Resistivity').text
trans = layer.find('Transparency').text
sheetPrio = layer.find('Sheet_Priority').text
#print(layerName,r,g,b,sourceLayer,material,port,res,trans,sheetPrio)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.