Pyqt5 關於流式佈局和滾動條的綜合使用

流式佈局

所謂流式佈局指的是容器中的元素像流水一樣,是可以浮動的,當元素一行或者一列佔滿的時候,它會自動流入到下一行或者下一列。

pyqt5流式佈局

pyqt中採用流式佈局的方法原理是,通過contentsMargins獲取到子元素距離佈局的上下左右寬度,然後我們將所有子元素進行遍歷,如果它加上邊距可以在一行放入的話,那麼就放在一行內,如果不能,就放入到下一行,具體代碼如下:

<code>m = self.contentsMargins()
effective_rect = rect.adjusted(+m.left(), +m.top(), -m.right(), -m.bottom())
x = effective_rect.x()
y = effective_rect.y()
line_height = 0

for item in self._item_list:
wid = item.widget()

space_x = self.spacing()
space_y = self.spacing()
if wid is not None:
space_x += wid.style().layoutSpacing(
QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
space_y += wid.style().layoutSpacing(
QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)

next_x = x + item.sizeHint().width() + space_x
if next_x - space_x > effective_rect.right() and line_height > 0:
x = effective_rect.x()
y = y + line_height + space_y
next_x = x + item.sizeHint().width() + space_x
line_height = 0

if not test_only:
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))

x = next_x
line_height = max(line_height, item.sizeHint().height())/<code>

滾動條的設置

pyqt中有專門的滾動條組件QScrollBar,這個組件需要配合其他組件使用,我們這裡使用QScrollArea這個組件進行滾動條的設置。

滾動條的使用方法

  • 首先,我們需要聲明QScrollArea
  • 然後,我們需要設置QScrollArea的位置大小
  • 最後,我們將需要產生滾動條的元素放入它的內部。
<code>q  = QWidget()
qscrollarea = QtWidgets.QScrollArea(q) qscrollarea.setGeometry(QRect(50,100,600,500))
qscrollarea.setWidgetResizable(True)
listWidget = QtWidgets.QListWidget()
qscrollarea.setWidget(listWidget)/<code>

流式佈局和滾動條的結合案例:

在文件當前目錄創建一個images文件夾,然後放入想要展示的多張圖片,然後執行當前程序,就會看到帶有滾動條的流式佈局界面。運行程序,需要安裝pyqt5

Pyqt5 關於流式佈局和滾動條的綜合使用

<code>from PyQt5.QtCore import QPoint, QRect, QSize, Qt,pyqtSignal
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (
QApplication, QLayout, QPushButton, QSizePolicy, QWidget, QGridLayout)
import sys
class Window(QWidget):
def __init__(self):
self.imageheight = 100
super(Window, self).__init__()
self.resize(800, 600)

#self.listwidget = QtWidgets.QListWidget(self)
#self.listwidget.resize(400,300)
#self.listwidget.setGeometry(QtCore.QRect(0, 0, 300, 200))
#self.listwidget.addItem("test")

highlight_dir = r"./images"
self.files_it = iter([os.path.join(highlight_dir, file)
for file in os.listdir(highlight_dir)])

# self.centralwidget = QtWidgets.QWidget(MainWindow)
# self.gongzuomoshi = QtWidgets.QGroupBox(self.centralwidget)
self.listWidget = QtWidgets.QListWidget(self)
#self.listWidget.setFixedWidth(600)
container_layout = QtWidgets.QVBoxLayout()
g = QtWidgets.QGroupBox('')
l = FlowLayout()
g.setLayout(l)
for file in iter(self.files_it):
pixmap = QtGui.QPixmap(file)
if not pixmap.isNull():
autoWidth = pixmap.width()*self.imageheight/pixmap.height()
label = QtWidgets.QLabel(pixmap=pixmap)
label.setScaledContents(True)
label.setFixedHeight(self.imageheight)
label.setFixedWidth(autoWidth)
l.addWidget(label)

container_layout.addWidget(g)
container_layout.addStretch()
self.listWidget.setLayout(container_layout)

self.qscrollarea = QtWidgets.QScrollArea(self)
self.qscrollarea.setGeometry(QRect(50,100,600,500))
self.qscrollarea.setWidgetResizable(True)
self.qscrollarea.setWidget(self.listWidget)
self.setWindowTitle("Flow Layout Scroll")


class FlowLayout(QLayout):
"""流式佈局,使用說明
1.聲明流式佈局 layout = FlowLayout
2.將元素放入流式佈局中
3.將QGroupBox應用流式佈局
4.如果期望水平流式,將QGroupBox放入到QHBoxLayout,如果期望垂直佈局,將QGroupBox放入到QVBoxLayout
"""
heightChanged = pyqtSignal(int)

def __init__(self, parent=None, margin=0, spacing=-1):
super().__init__(parent)
if parent is not None:
self.setContentsMargins(margin, margin, margin, margin)
self.setSpacing(spacing)

self._item_list = []

def __del__(self):
while self.count():
self.takeAt(0)

def addItem(self, item): # pylint: disable=invalid-name
self._item_list.append(item)

def addSpacing(self, size): # pylint: disable=invalid-name
self.addItem(QSpacerItem(size, 0, QSizePolicy.Fixed, QSizePolicy.Minimum))

def count(self):
return len(self._item_list)

def itemAt(self, index): # pylint: disable=invalid-name
if 0 <= index < len(self._item_list):
return self._item_list[index]
return None

def takeAt(self, index): # pylint: disable=invalid-name
if 0 <= index < len(self._item_list):
return self._item_list.pop(index)
return None

def expandingDirections(self): # pylint: disable=invalid-name,no-self-use
return Qt.Orientations(Qt.Orientation(0))

def hasHeightForWidth(self): # pylint: disable=invalid-name,no-self-use

return True

def heightForWidth(self, width): # pylint: disable=invalid-name
height = self._do_layout(QRect(0, 0, width, 0), True)
return height

def setGeometry(self, rect): # pylint: disable=invalid-name
super().setGeometry(rect)
self._do_layout(rect, False)

def sizeHint(self): # pylint: disable=invalid-name
return self.minimumSize()

def minimumSize(self): # pylint: disable=invalid-name
size = QSize()

for item in self._item_list:
minsize = item.minimumSize()
extent = item.geometry().bottomRight()
size = size.expandedTo(QSize(minsize.width(), extent.y()))

margin = self.contentsMargins().left()
size += QSize(2 * margin, 2 * margin)
return size

def _do_layout(self, rect, test_only=False):
m = self.contentsMargins()
effective_rect = rect.adjusted(+m.left(), +m.top(), -m.right(), -m.bottom())
x = effective_rect.x()
y = effective_rect.y()
line_height = 0

for item in self._item_list:
wid = item.widget()

space_x = self.spacing()
space_y = self.spacing()
if wid is not None:
space_x += wid.style().layoutSpacing(
QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
space_y += wid.style().layoutSpacing(
QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)

next_x = x + item.sizeHint().width() + space_x
if next_x - space_x > effective_rect.right() and line_height > 0:
x = effective_rect.x()
y = y + line_height + space_y
next_x = x + item.sizeHint().width() + space_x
line_height = 0

if not test_only:
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))

x = next_x
line_height = max(line_height, item.sizeHint().height())

new_height = y + line_height - rect.y()
self.heightChanged.emit(new_height)
return new_height

if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = Window()

mainWin.show()
sys.exit(app.exec_())/<code>


分享到:


相關文章: