Python PyQt:环绕QScrollara中小部件的布局
我正在开发一个使用PyQt4记忆文本的应用程序。我想把所有的单词都放在泡泡里,这样你就可以看到这个单词有多长了。但是当我的Python PyQt:环绕QScrollara中小部件的布局,python,layout,pyqt,alignment,qscrollarea,Python,Layout,Pyqt,Alignment,Qscrollarea,我正在开发一个使用PyQt4记忆文本的应用程序。我想把所有的单词都放在泡泡里,这样你就可以看到这个单词有多长了。但是当我的qscrollara中有所有气泡时,它们一个接一个地对齐。我想让它们并排对齐,但要用换行符 我使用带有圆形边框的QLabel使气泡工作。但现在我有了《代码> QLabor的< /C> >中的文字,PyQt不把它们当作词——而是作为小部件。因此PyQt将一个小部件置于另一个小部件之下。我希望小部件并排对齐,直到它们到达行的末尾,然后它们应该环绕到下一行-这意味着QLabel的应
qscrollara
中有所有气泡时,它们一个接一个地对齐。我想让它们并排对齐,但要用换行符
我使用带有圆形边框的QLabel
使气泡工作。但现在我有了《代码> QLabor的< /C> >中的文字,PyQt不把它们当作词——而是作为小部件。因此PyQt将一个小部件置于另一个小部件之下。我希望小部件并排对齐,直到它们到达行的末尾,然后它们应该环绕到下一行-这意味着QLabel的
应该像文本文档中的单词一样工作
以下是我目前的代码:
f = open(r'myFile.txt')
class Bubble(QtGui.QLabel):
def __init__(self, text):
super(Bubble, self).__init__(text)
self.word = text
self.setContentsMargins(5, 5, 5, 5)
def paintEvent(self, e):
p = QtGui.QPainter(self)
p.setRenderHint(QtGui.QPainter.Antialiasing,True)
p.drawRoundedRect(0,0,self.width()-1,self.height()-1,5,5)
super(Bubble, self).paintEvent(e)
class MainWindow(QtGui.QMainWindow):
def __init__(self, text, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.MainArea = QtGui.QScrollArea
self.widget = QtGui.QWidget()
vbox = QtGui.QVBoxLayout()
self.words = []
for t in re.findall(r'\b\w+\b', text):
label = Bubble(t)
label.setFont(QtGui.QFont('SblHebrew', 18))
label.setFixedWidth(label.sizeHint().width())
self.words.append(label)
vbox.addWidget(label)
self.widget.setLayout(vbox)
self.MainArea.setWidget(self.widget)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
myWindow = MainWindow(f.read(), None)
myWindow.show()
sys.exit(app.exec_())
当我运行此命令时,我得到:
但我希望单词(包含单词的Qlabel的
)彼此相邻,而不是相互下方,如下图所示(photoshopped):
我已经做了很多研究,但没有任何答案可以帮助我将小部件彼此对齐 我认为可以在
QTextBrowser
小部件中使用html来实现这一点,但Qt不支持气泡标签所需的border radius
CSS属性
所以看起来您需要一个的PyQt端口。这可以在容器中“字包装”一组小部件,还允许调整边距和水平/垂直间距
下面是一个演示脚本,它实现了FlowLayout
类,并演示了如何在示例中使用它:
import sys
from PyQt4 import QtCore, QtGui
class FlowLayout(QtGui.QLayout):
def __init__(self, parent=None, margin=-1, hspacing=-1, vspacing=-1):
super(FlowLayout, self).__init__(parent)
self._hspacing = hspacing
self._vspacing = vspacing
self._items = []
self.setContentsMargins(margin, margin, margin, margin)
def __del__(self):
del self._items[:]
def addItem(self, item):
self._items.append(item)
def horizontalSpacing(self):
if self._hspacing >= 0:
return self._hspacing
else:
return self.smartSpacing(
QtGui.QStyle.PM_LayoutHorizontalSpacing)
def verticalSpacing(self):
if self._vspacing >= 0:
return self._vspacing
else:
return self.smartSpacing(
QtGui.QStyle.PM_LayoutVerticalSpacing)
def count(self):
return len(self._items)
def itemAt(self, index):
if 0 <= index < len(self._items):
return self._items[index]
def takeAt(self, index):
if 0 <= index < len(self._items):
return self._items.pop(index)
def expandingDirections(self):
return QtCore.Qt.Orientations(0)
def hasHeightForWidth(self):
return True
def heightForWidth(self, width):
return self.doLayout(QtCore.QRect(0, 0, width, 0), True)
def setGeometry(self, rect):
super(FlowLayout, self).setGeometry(rect)
self.doLayout(rect, False)
def sizeHint(self):
return self.minimumSize()
def minimumSize(self):
size = QtCore.QSize()
for item in self._items:
size = size.expandedTo(item.minimumSize())
left, top, right, bottom = self.getContentsMargins()
size += QtCore.QSize(left + right, top + bottom)
return size
def doLayout(self, rect, testonly):
left, top, right, bottom = self.getContentsMargins()
effective = rect.adjusted(+left, +top, -right, -bottom)
x = effective.x()
y = effective.y()
lineheight = 0
for item in self._items:
widget = item.widget()
hspace = self.horizontalSpacing()
if hspace == -1:
hspace = widget.style().layoutSpacing(
QtGui.QSizePolicy.PushButton,
QtGui.QSizePolicy.PushButton, QtCore.Qt.Horizontal)
vspace = self.verticalSpacing()
if vspace == -1:
vspace = widget.style().layoutSpacing(
QtGui.QSizePolicy.PushButton,
QtGui.QSizePolicy.PushButton, QtCore.Qt.Vertical)
nextX = x + item.sizeHint().width() + hspace
if nextX - hspace > effective.right() and lineheight > 0:
x = effective.x()
y = y + lineheight + vspace
nextX = x + item.sizeHint().width() + hspace
lineheight = 0
if not testonly:
item.setGeometry(
QtCore.QRect(QtCore.QPoint(x, y), item.sizeHint()))
x = nextX
lineheight = max(lineheight, item.sizeHint().height())
return y + lineheight - rect.y() + bottom
def smartSpacing(self, pm):
parent = self.parent()
if parent is None:
return -1
elif parent.isWidgetType():
return parent.style().pixelMetric(pm, None, parent)
else:
return parent.spacing()
class Bubble(QtGui.QLabel):
def __init__(self, text):
super(Bubble, self).__init__(text)
self.word = text
self.setContentsMargins(5, 5, 5, 5)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.drawRoundedRect(
0, 0, self.width() - 1, self.height() - 1, 5, 5)
super(Bubble, self).paintEvent(event)
class MainWindow(QtGui.QMainWindow):
def __init__(self, text, parent=None):
super(MainWindow, self).__init__(parent)
self.mainArea = QtGui.QScrollArea(self)
self.mainArea.setWidgetResizable(True)
widget = QtGui.QWidget(self.mainArea)
widget.setMinimumWidth(50)
layout = FlowLayout(widget)
self.words = []
for word in text.split():
label = Bubble(word)
label.setFont(QtGui.QFont('SblHebrew', 18))
label.setFixedWidth(label.sizeHint().width())
self.words.append(label)
layout.addWidget(label)
self.mainArea.setWidget(widget)
self.setCentralWidget(self.mainArea)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MainWindow('Harry Potter is a series of fantasy literature')
window.show()
sys.exit(app.exec_())
导入系统
从PyQt4导入QtCore、QtGui
类流布局(QtGui.QLayout):
定义初始化(self,parent=None,margin=-1,hspacing=-1,vspacing=-1):
超级(FlowLayout,self)。\uuuuu初始化\uuuuuu(父级)
自排=自排
self.\u vspacking=vspacking
self._项=[]
self.setContentsMargins(边距、边距、边距、边距)
定义(自我):
删除自身项目[:]
def附加项(自身,项目):
self.\u items.append(项目)
def水平间距(自):
如果self.\u hspacing>=0:
返回自我
其他:
返回自定间距(
QtGui.QStyle.PM_布局权限(水平间距)
def垂直间距(自):
如果self.\u vspacing>=0:
返回自我空间
其他:
返回自定间距(
QtGui.QStyle.PM_布局垂直间距)
def计数(自身):
返回len(自身项目)
def itemAt(自身,索引):
如果0:
x=有效。x()
y=y+线宽+vspace
nextX=x+item.sizeHint().width()+hspace
线宽=0
如果不只是测试:
item.setGeometry(
QtCore.QRect(QtCore.QPoint(x,y),item.sizeHint())
x=nextX
lineheight=max(lineheight,item.sizeHint().height())
返回y+线宽-矩形y()+底部
def智能间距(自、pm):
parent=self.parent()
如果父项为“无”:
返回-1
elif parent.isWidgetType():
返回parent.style().pixelMetric(pm,None,parent)
其他:
返回parent.spating()
类气泡(QtGui.QLabel):
定义初始化(self,text):
超级(气泡,自我)。\uuuuu初始化\uuuuuuu(文本)
self.word=文本
self.setContentsMargins(5,5,5,5)
def paintEvent(自身,事件):
painter=QtGui.QPainter(自)
painter.setRenderHint(QtGui.QPainter.Antialiasing,True)
油漆工(
0,0,self.width()-1,self.height()-1,5,5)
超级(泡泡,自我)。绘画事件(事件)
类主窗口(QtGui.QMainWindow):
def uuu init uuu(self,text,parent=None):
超级(主窗口,自我)。\uuuuu初始化\uuuuuuu(父级)
self.mainArea=QtGui.QScrollArea(self)
self.mainArea.SetWidgetResizeable(True)
widget=QtGui.QWidget(self.mainArea)
widget.setMinimumWidth(50)
布局=流程布局(小部件)
self.words=[]
对于text.split()中的单词:
标签=气泡(字)
label.setFont(QtGui.QFont('SblHebrew',18))
label.setFixedWidth(label.sizeHint().width())
self.words.append(标签)
layout.addWidget(标签)
self.mainArea.setWidget(小部件)
self.setCentralWidget(self.main区域)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app=QtGui.QApplication(sys.argv)
window=MainWindow(《哈利波特》是一系列奇幻文学作品)
window.show()
sys.exit(app.exec_())
以下是流程布局演示脚本的PyQt5版本:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class FlowLayout(QtWidgets.QLayout):
def __init__(self, parent=None, margin=-1, hspacing=-1, vspacing=-1):
super(FlowLayout, self).__init__(parent)
self._hspacing = hspacing
self._vspacing = vspacing
self._items = []
self.setContentsMargins(margin, margin, margin, margin)
def __del__(self):
del self._items[:]
def addItem(self, item):
self._items.append(item)
def horizontalSpacing(self):
if self._hspacing >= 0:
return self._hspacing
else:
return self.smartSpacing(
QtWidgets.QStyle.PM_LayoutHorizontalSpacing)
def verticalSpacing(self):
if self._vspacing >= 0:
return self._vspacing
else:
return self.smartSpacing(
QtWidgets.QStyle.PM_LayoutVerticalSpacing)
def count(self):
return len(self._items)
def itemAt(self, index):
if 0 <= index < len(self._items):
return self._items[index]
def takeAt(self, index):
if 0 <= index < len(self._items):
return self._items.pop(index)
def expandingDirections(self):
return QtCore.Qt.Orientations(0)
def hasHeightForWidth(self):
return True
def heightForWidth(self, width):
return self.doLayout(QtCore.QRect(0, 0, width, 0), True)
def setGeometry(self, rect):
super(FlowLayout, self).setGeometry(rect)
self.doLayout(rect, False)
def sizeHint(self):
return self.minimumSize()
def minimumSize(self):
size = QtCore.QSize()
for item in self._items:
size = size.expandedTo(item.minimumSize())
left, top, right, bottom = self.getContentsMargins()
size += QtCore.QSize(left + right, top + bottom)
return size
def doLayout(self, rect, testonly):
left, top, right, bottom = self.getContentsMargins()
effective = rect.adjusted(+left, +top, -right, -bottom)
x = effective.x()
y = effective.y()
lineheight = 0
for item in self._items:
widget = item.widget()
hspace = self.horizontalSpacing()
if hspace == -1:
hspace = widget.style().layoutSpacing(
QtWidgets.QSizePolicy.PushButton,
QtWidgets.QSizePolicy.PushButton, QtCore.Qt.Horizontal)
vspace = self.verticalSpacing()
if vspace == -1:
vspace = widget.style().layoutSpacing(
QtWidgets.QSizePolicy.PushButton,
QtWidgets.QSizePolicy.PushButton, QtCore.Qt.Vertical)
nextX = x + item.sizeHint().width() + hspace
if nextX - hspace > effective.right() and lineheight > 0:
x = effective.x()
y = y + lineheight + vspace
nextX = x + item.sizeHint().width() + hspace
lineheight = 0
if not testonly:
item.setGeometry(
QtCore.QRect(QtCore.QPoint(x, y), item.sizeHint()))
x = nextX
lineheight = max(lineheight, item.sizeHint().height())
return y + lineheight - rect.y() + bottom
def smartSpacing(self, pm):
parent = self.parent()
if parent is None:
return -1
elif parent.isWidgetType():
return parent.style().pixelMetric(pm, None, parent)
else:
return parent.spacing()
class Bubble(QtWidgets.QLabel):
def __init__(self, text):
super(Bubble, self).__init__(text)
self.word = text
self.setContentsMargins(5, 5, 5, 5)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.drawRoundedRect(
0, 0, self.width() - 1, self.height() - 1, 5, 5)
super(Bubble, self).paintEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, text, parent=None):
super(MainWindow, self).__init__(parent)
self.mainArea = QtWidgets.QScrollArea(self)
self.mainArea.setWidgetResizable(True)
widget = QtWidgets.QWidget(self.mainArea)
widget.setMinimumWidth(50)
layout = FlowLayout(widget)
self.words = []
for word in text.split():
label = Bubble(word)
label.setFont(QtGui.QFont('SblHebrew', 18))
label.setFixedWidth(label.sizeHint().width())
self.words.append(label)
layout.addWidget(label)
self.mainArea.setWidget(widget)
self.setCentralWidget(self.mainArea)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow('Harry Potter is a series of fantasy literature')
window.show()
sys.exit(app.exec_())
导入系统
从PyQt5导入QtCore、QtGui、QtWidgets
类FlowLayout(QtWidgets.QLayout):
定义初始化(self,parent=None,margin=-1,hspacing=-1,vspacing=-1):
超级(FlowLayout,self)。\uuuuu初始化\uuuuuu(父级)
自排=自排
self.\u vspacking=vspacking
self._项=[]
self.setContentsMargins(边距、边距、边距、边距)
定义(自我):
删除自身项目[:]
def附加项(自身,项目):
self.\u items.append(项目)
def水平间距(自):
如果self.\u hspacing>=0:
返回自我
其他:
返回自定间距(
qtwidts.QStyle.PM_layoutAuthorizontalSpacing)
def垂直间距(自):
如果self.\u vspacing>=0:
返回自我空间
其他:
返回自定间距(
qtwidts.QStyle.PM_布局垂直间距)
def计数(自身):
返回len(自身项目)
def itemAt(自身,索引):
如果0:
x=有效。x()
y=y+线宽+vspace
nextX=x+item.sizeHint().width()+hspace
线宽=0
如果不只是测试: