wxPython 解决 Vertical alignment flags are ignored in vertical sizers

更新了wxPython之后,运行程序,发现以前OK的程序莫名报错了……

wx._core.wxAssertionError: C++ assertion “!(flags & wxALIGN_BOTTOM)” failed at …\src\common\sizer.cpp(2136) in wxBoxSizer::DoInsert(): Vertical alignment flags are ignored in vertical sizers
python-BaseException

老版本的wxPython能忽略类似这样的错误,但是4.1之后就不被忽略了……

对于我们这些使用wxFormBuilder的人来说…… 遇到了一点点小麻烦……

当我们改变了某个Sizer的wxVERTICAL或wxHORIZONTAL后,在运行时就会遇到类似的错误

在这里插入图片描述
但是~ 此时的wxFormBuilder界面的ToolBar上无法对报错的对齐属性进行编辑了……

下图:我遇到的报错是 m_staticText2 的 wxALIGN_BOTTOM 不能被使用于 Sizer 的 wxVERTICAL 模式下,我需要把它去掉,但无法快捷使用ToolBar上的按钮了。

在这里插入图片描述
只能这样做:

打开有问题的控件的属性页的最后一项:flag,把有问题的属性去掉即可。
在这里插入图片描述

另外,这样的问题,每执行一次只能找到一个。如果想批量找出来的话,就只能自己写段分析代码了。

原始的.fbp文件是xml格式的,可以分析每个sizer的下一层(注1)里的控件是否flag属性里有冲突项。

注1:不是XML的层,实际的XML中多了一层 sizeritem

反正就是如下几种情况:
1. 竖着放的Sizer下的控件不能有Align Top Button 竖居中
2. 横着放的Sizer下的控件不能有Align Left Right 横居中
3. Sizer 和 Spacer 不能存在Align属性…

import time
import xml.etree.ElementTree as EleTree


class CheckFbp:
    def __init__(self, fn):
        with open(fn, "r") as f:
            s = f.read()
        self.fn = fn
        self.root = EleTree.fromstring(s)
        self.treeLvName = list()
        self.errList = list()
    
    def makeOneLevel(self, ele):
        thisLv = dict()
        children = list()
        for i in ele:  # type: EleTree.Element
            if i.tag == "object":
                if i.attrib['class'] == "spacer" or i.attrib['class'].endswith("Sizer"):
                    thisLv['class'] = i.attrib['class']
                childLv = self.makeOneLevel(i)
                children.append(childLv)
            try:
                if i.attrib['name'] == "name":
                    thisLv['name'] = i.text
            except Exception:
                pass
            try:
                if i.attrib['name'] == "orient":
                    thisLv['orient'] = i.text
            except Exception:
                pass
            try:
                if i.attrib['name'] == "flag" and i.text:
                    thisLv['flag'] = i.text
            except Exception:
                pass
        thisLv['children'] = children
        return thisLv
    
    def makeTree(self):
        self.theTree = self.makeOneLevel(self.root)
    
    def check(self):
        self.makeTree()
        for i in self.theTree['children']:
            self.checkOneLv(i)
        for i in self.errList:
            print(i)
    
    def checkOneLv(self, data):
        self.treeLvName.append(data['name'] if "name" in data.keys() else "(SIZERITEM)")
        if "class" in data.keys():
            if data['class'] == "spacer":
                if "flag" in data.keys() and data['flag'].find("wxALIGN_") >= 0:
                    self.errList.append("spacerNoAlign: %s, %s" % (self.getNameTreeNow(), "spacer"))
            else:
                if "flag" in data.keys() and data['flag'].find("wxALIGN_") >= 0:
                    self.errList.append("sizerNoAlign: %s, %s" % (self.getNameTreeNow(), data['children'][0]['name']))
        if data['children']:
            for i in data['children']:
                self.checkOneLv(i)
            if "orient" in data.keys():
                for i in data['children']:
                    if "flag" in i.keys() and "class" not in i.keys() and i['flag'] is not None:
                        if data['orient'] == "wxVERTICAL":
                            if i['flag'].find("wxALIGN_TOP") >= 0 \
                                    or i['flag'].find("wxALIGN_BOTTOM") >= 0 \
                                    or i['flag'].find("wxALIGN_CENTER_VERTICAL") >= 0:
                                self.errList.append("NoTopBottomV: %s, %s" % (self.getNameTreeNow(),
                                                                              i['children'][0]['name']))
                        else:
                            if i['flag'].find("wxALIGN_LEFT") >= 0 \
                                    or i['flag'].find("wxALIGN_RIGHT") >= 0 \
                                    or i['flag'].find("wxALIGN_CENTER_HORIZONTAL") >= 0:
                                self.errList.append("NoLeftRightH: %s, %s" % (self.getNameTreeNow(),
                                                                              i['children'][0]['name']))
        self.treeLvName.pop(-1)
    
    def getNameTreeNow(self):
        s = ", ".join(self.treeLvName)
        return s.replace(", (SIZERITEM)", "")
    
    def isInErrList(self):
        tmpList = list()
        for i in self.nameList_whenUpdate:
            tmpList.append(i['name'])
        s = ", ".join(tmpList)
        s = s.replace(", (SIZERITEM)", "")
        for i in self.errList:
            ss = i.split(": ")
            if ss[1] == s:
                return True, ss[0]
        return False, ""
    
    def updateSizerItemLine(self, line, n, m):
        ss = line[n:m].split("|")
        for i, s in enumerate(ss):
            if s.find("wxALIGN_") >= 0:
                ss.pop(i)
        s = "|".join(ss)
        s = line[:n] + s + line[m:]
        return s
    
    def updateErrFlagLine(self, flag2, line, n, m):
        ss = line[n:m].split("|")
        for i, s in enumerate(ss):
            if flag2 == "NoTopBottomV":
                if s in ["wxALIGN_TOP", "wxALIGN_BOTTOM", "wxALIGN_CENTER_VERTICAL"]:
                    ss.pop(i)
            else:  # flag2 == "NoLeftRightH"
                if s in ["wxALIGN_LEFT", "wxALIGN_RIGHT", "wxALIGN_CENTER_HORIZONTAL"]:
                    ss.pop(i)
        s = "|".join(ss)
        s = line[:n] + s + line[m:]
        return s
    
    def updateSizerAndSpacer(self, lines):
        i = 0
        while i < len(lines):
            if lines[i].find('<object class=') >= 0:
                className = lines[i].split('"')[1]
                if className.endswith("Sizer") or className == "spacer":
                    j = i
                    while True:
                        j -= 1
                        n = lines[j].find('<property name="flag">')
                        if n >= 0:
                            n += 22
                            m = lines[j].find("<", n)
                            lines.insert(j, self.updateSizerItemLine(lines.pop(j), n, m))
                            break
                        if lines[j].find('<object class=') >= 0:
                            break
            i += 1
    
    def make_UPDATE_fbp(self):
        if not self.errList:
            print("No Error... checked ???")
            return
        for i, n in enumerate(self.errList):
            if not n.startswith("No"):
                self.errList.pop(i)
        
        with open(self.fn, "r") as f:
            lines = f.readlines()
        self.nameList_whenUpdate = list()
        
        self.updateSizerAndSpacer(lines)
        
        newDict = dict()
        i = -1
        while i < len(lines) - 1:
            i += 1
            line = lines[i]
            if line.find('<object class=') >= 0:
                classStr = line.split('"')[1]
                newDict = {
                    'name': "(SIZERITEM)",
                    'class': classStr
                    }
                self.nameList_whenUpdate.append(newDict)
                continue
            
            if line.find("</object>") >= 0:
                self.nameList_whenUpdate.pop(-1)
                continue
            
            n = line.find('<property name="name">')
            if n >= 0:
                n += 22
                m = line.find("<", n)
                name = line[n:m]
                newDict['name'] = name
                flag1, flag2 = self.isInErrList()
                if flag1:
                    j = i
                    while True:
                        j -= 1
                        n = lines[j].find('<property name="flag">')
                        if n >= 0:
                            n += 22
                            m = lines[j].find("<", n)
                            lines.insert(j, self.updateErrFlagLine(flag2, lines.pop(j), n, m))
                            break
        with open(self.fn + time.strftime("_%Y%m%d%H%M%S", time.localtime()), "w") as f:
            f.writelines(lines)



if __name__ == '__main__':
    cf = CheckFbp(r"C:\ABC\test.fbp")
    cf.check()
    cf.make_UPDATE_fbp()
    

然后会输出结果:(会显示整条有问题的Tree Name)
NoLeftRightH: MyProject1, MyPanel14, fgSizer22, bSizer93, m_button58
NoTopBottomV: MyProject1, MyPanelSnComp, m_checkBox11
sizerNoAlign: MyProject1, MyDialog1, bSizer4, bSizer15
spacerNoAlign: MyProject1, MyDialog1, bSizer4, bSizer15, spacer

check() 负责检查与输出
make_UPDATE_fbp() 在check()之后自动修正fbp文件,并在原始文件名后加入时间戳。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值