QFrame在 QDialog中不可见

前端开发 2026-07-09

我在QGIS中使用Windows 11、Python 3.12.12,以及PyQt 5.15.13。不确定这是否是QGIS的特定问题,所以我先在这里试试,而不是去GIS Stack Exchange。

我想给一个 QDialog 增加边框,以把几个布局分隔开来:

layout1 = QVBoxLayout()
layout1.addLayout(sublayout1) #QHBoxLayout
layout1.addLayout(sublayout2) #QHBoxLayout
layout1.addWidget(checkbox1) #QWidget
qframe1 = QFrame()
qframe1.setFrameStyle(QFrame.Panel | QFrame.Plain)
qframe1.setLineWidth(3)
#qframe1.setStyleSheet("background-color: rgb(255,0,0")
qframe1.setLayout(layout1)
self.layout = QVBoxLayout()
#self.layout.addLayout(qframe1) #No exception in my main project
self.layout.addWidget(qframe1)
self.layout.addWidget(checkbox2) #QWidget
self.layout.addSpacing(10)
self.layout.addLayout(layout2) #QHBoxLayout
self.setLayout(self.layout) #self=QDialog

这把所有元素往中心挪动了,因此 QFrame 肯定在那里,但看不见。若我使用 QFrame.Box 也是同样的问题,背景颜色也没帮助让它显现(我宁愿不通过样式表来修复这个)。

我也尝试改用水平线:

qframe1 = QFrame()
qframe1.setFrameStyle(QFrame.HLine | QFrame.Raised)
qframe1.setLineWidth(3)
layout1 = QVBoxLayout()
layout1.addLayout(sublayout1) #QHBoxLayout
layout1.addLayout(sublayout2) #QHBoxLayout
layout1.addWidget(qframe1)
layout1.addWidget(checkbox1) #QWidget
self.layout = QVBoxLayout()
self.layout.addLayout(layout1)
self.layout.addWidget(checkbox2) #QWidget
self.layout.addSpacing(10)
self.layout.addLayout(layout2) #QHBoxLayout
self.setLayout(self.layout)

现在 sublayout2checkbox1 之间的间距变大,但这条线不可见。

我尝试像这里 所建议的那样把 QgsApplication.setStyle("Fusion") 放在顶部——不过,这一切都发生在QGIS插件中的一个 QDialog 里,而不是在常规的独立Windows应用程序中——但它在样式加载时只让QGIS暂时卡住了一秒钟,仍然没有显示 QFrame

我到底错在哪儿?

编辑:

我现在还尝试了另外两种设置颜色边框的方法,如 这个 问题及其回答所示:

color = QColor(255,0,0)
qframe1.setStyleSheet("border:1px solid %s" % color)

以及

color = QColor(255,0,0)
pal = qframe1.palette()
pal.setColor(QPalette.WindowText, color)
qframe1.setPalette(pal)

结果都是一样的:边框不可见。

最小可复现示例:

from PyQt5.QtWidgets import (QDialog, QHBoxLayout, QVBoxLayout, QCheckBox, QDialogButtonBox, QFrame)

class MyDialog(QDialog):
    def __init__(self):
        super().__init__()
        addborder = True #border or line
        layout1 = QHBoxLayout()
        checkbox1 = QCheckBox("Checkbox 1")
        checkbox2 = QCheckBox("Checkbox 2")
        layout1.addWidget(checkbox1)
        layout1.addWidget(checkbox2)

        qframe1 = QFrame()
        if addborder: qframe1.setFrameStyle(QFrame.Panel | QFrame.Plain)
        else: qframe1.setFrameStyle(QFrame.HLine | QFrame.Raised)
        qframe1.setLineWidth(3)

        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self.accept)
        button_box.rejected.connect(self.reject)

        checkbox3 = QCheckBox("Checkbox 3")

        self.layout = QVBoxLayout()
        if addborder:
            qframe1.setLayout(layout1)
            self.layout.addWidget(qframe1)
        else:
            self.layout.addLayout(layout1)
            self.layout.addWidget(qframe1)
        self.layout.addWidget(checkbox3)
        self.layout.addSpacing(10)
        self.layout.addWidget(button_box)
        self.setLayout(self.layout)

md = MyDialog()
md.exec()

使用 addborder = True 的结果:

enter image description here

解决方案

QGIS内置的两个UI主题(“Blend of Gray”和“Night Mapping”)是 Qt Stylesheets(QSS),其中包含针对 QFrameQGroupBox 小部件的规则,这些规则会隐藏边框。具体来说,QGIS的源代码 中包含这两条规则:

QGroupBox {
    padding-top: 1.05em;
    border:1px solid rgba(0,0,0,0);
}
QFrame, QFrame:disabled {
    border:1px solid rgba(0,0,0,0);
}

它们使边框变得透明(因为颜色的alpha分量被设为零)。这似乎表明隐藏边框是QGIS的一种有意设计选择。

如果UI主题被设置为 "default",QGIS会回退到Qt的小部件样式,这种样式根本不使用QSS。在这种配置下,无法确定边框是否会显示——内置的 "Fusion" 小部件样式会显示边框,但显然也有其他Qt小部件样式不会。

因此,一个简单的解决方法是覆盖上述两条规则,并将 border-color属性 替换为更合适的值。例如,像下面这样:

qframe1.setStyleSheet('QFrame, QFrame:disabled {border: 1px solid grey}')

然而,如果使用的是Qt小部件样式(而不是某个QSS主题),这类修复可能会产生不可预知的结果。因此,理想情况下,只有在使用QSS主题时才应该应用它。(大概,[QApplication.instance().styleSheet()] 应在这种情况下返回非空字符串——但我自己无法亲自测试)。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章