'Custom QScrollArea
I have developed some functionality that generates the following rows of output: 6 QLabels with pixmaps assigned to them, as well as 6 additional QLabels with assigned text that are positioned over the pixmap QLabels. Below the above set of labels, I include an additional QLabel with more information, before the cycle repeats. Below is an example image:
The output generated is based on the length of the list object the function is pulling in and will sometimes be larger than can be displayed in the window. I've made several attempts to create a scroll area to add my output to, but nothing works to recreate the layout shown above. QVBoxLayout and QHBoxLayout will stack each individual QLabel separately, either vertically or horizontally, which isn't the visual I'm trying to create (as shown above). Below is an example of output that is longer than can be shown in the window:
Not sure if there's some other way to create the layout I'm trying to put together, but if anyone can figure out a solution that doesn't incorporate QVBoxLayout or QHBoxLayout for adding scroll bars to a window, that would be great. Below is the code that generates the incorrect output:
def create_sample_images(self, sample_numbers):
# example of sample_numbers = [01,18,2022,1,2,3,4,5,6,2.0,$100 Million,Roll]
# print(sample_numbers)
# print(len(sample_numbers))
# creating the scroll area, widget and vbox
self.scroll = QScrollArea()
self.widget = QWidget()
self.vbox = QVBoxLayout()
if len(sample_numbers) != 0:
i = 1
x = 40
y = 75
w = 100
h = 100
for item in sample_numbers:
# print("Here is an item")
result = item[3:9]
datevalue = item[:3]
jackpotvalue = item[10]
outcome = item[11]
historylabel = ["DATE: " + str(datevalue[0]) + '-' + str(datevalue[1])
+ '-' + str(datevalue[2])
+ ' | ' + "PRIZE: " + jackpotvalue
+ ' | ' + "ROLL (NO WINNER)"]
result.append(historylabel)
# print(result)
# print(type(result))
# print(datevalue)
# print(jackpotvalue)
# print(outcome)
# print(historylabel)
for obj in result:
# print("Here is an obj in item")
self.outputlabel = QLabel(self)
self.labeltext = QLabel(self)
self.labeltext.setText(str(obj))
self.labeltext.setAlignment(QtCore.Qt.AlignCenter)
self.labeltext.setStyleSheet("QLabel { color : black; }")
if i < 6:
self.pixmap = QPixmap(u":/graphics/Images/lottoball.png")
else:
self.pixmap = QPixmap(u":/graphics/Images/lottoslip.jpg")
self.outputlabel.setPixmap(self.pixmap)
self.outputlabel.resize(self.pixmap.width(),
self.pixmap.height())
self.outputlabel.setGeometry(x, y, w, h)
self.labeltext.setGeometry(x, y, w, h)
# adding labels to vbox
self.vbox.addWidget(self.outputlabel)
self.vbox.addWidget(self.labeltext)
x += 125
i += 1
if i == 7:
i += 1
x = 40
y += 125
elif i > 7:
self.outputlabel.setPixmap(None)
self.labeltext.setText(historylabel[0])
self.labeltext.setStyleSheet("QLabel { color : white; }")
self.labeltext.adjustSize()
# adding label to vbox
self.vbox.addWidget(self.labeltext)
i = 1
x = 40
y += 50
self.widget.setLayout(self.vbox)
# Scroll Area Properties
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.widget)
self.setCentralWidget(self.scroll)
self.show()
Below is an example of the bad output. All widgets are being stacked on top of each other and displayed vertically or horizontally (vbox/hbox):
Solution 1:[1]
you can use "gridlayout" or set limit for your items with use "setMinimumSize" below like this example
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
class main(QMainWindow):
def __init__(self):
super().__init__()
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
self.widget = QWidget()
self.scroll.setWidgetResizable(True)
# => grid set
self.grid = QGridLayout(self.widget)
self.grid.setContentsMargins(10,40,10,20)
self.grid.setHorizontalSpacing(20)
self.grid.setVerticalSpacing(10)
for i in range(6):
for j in range(3):
if i % 2 == 1:
self.grid.addWidget(QLabel("DateTime => 01.19.2022 | $400 | ROLL"), i,j, 1,3)
break
else:
self.label = QLabel("9")
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.label.setStyleSheet("background-color: red;")
# => item set minimum size !
self.label.setMinimumSize(120,120)
self.grid.addWidget(self.label, i, j, 1,1)
self.scroll.setWidget(self.widget)
self.setCentralWidget(self.scroll)
self.resize(600,550)
self.show()
app = QApplication([])
window = main()
app.exec()
Solution 2:[2]
Using SimoN SavioR's tips and example code above, I figured out how to reconstruct my function to produce the results I was looking for, which mimic what SimoN produced in his example. Primarily, the biggest issues I think I had in my previous code is using Vbox instead of Grid, and assigning the Widget to Vbox instead of assigning the Widget to a layout. Below is my new code for my function which now works as desired, along with an example screenshot of the new output I'm getting. After studying SimoN's code and understanding how it produced the output, I managed to integrate certain chunks of code into my own original code in order to get the function to work appropriately and display the output the way I wanted it originally. The main code blocks I borrowed from SimoN were the two blocks before the for loop, and the block right after the for loop. I was able to keep all the rest of my original code, with some slight modifications to get it all to work together.
def create_sample_images(self, sample_numbers):
displaytext = "Displaying " + str(len(sample_numbers)) + " results"
self.setWindowTitle(displaytext)
# print(sample_numbers)
# print(len(sample_numbers))
# self.gridlayout = QGridLayout()
# # self.groupbox = QGroupBox("Results")
# self.vbox = QVBoxLayout()
# self.scroll = QScrollArea()
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.widget = QWidget()
self.scroll.setWidgetResizable(True)
# => grid set
self.gridlayout = QGridLayout(self.widget) # widget is parent widget
self.gridlayout.setContentsMargins(10, 40, 10, 20) # left, top, right, bottom
self.gridlayout.setHorizontalSpacing(20)
self.gridlayout.setVerticalSpacing(10)
if len(sample_numbers) != 0:
i = 1
ballrow = 0
inforow = 1
ballcolumn = 0
infocolumn = 0
for item in sample_numbers:
# print("Here is an item")
result = item[3:9]
datevalue = item[:3]
jackpotvalue = item[10]
outcome = item[11]
if outcome == "Roll":
historylabel = ["Date: " + str(datevalue[0]) + '-' + str(datevalue[1])
+ '-' + str(datevalue[2])
+ ' | ' + "Prize: " + jackpotvalue
+ ' | ' + "Roll (No Winner)"]
else:
historylabel = ["Date: " + str(datevalue[0]) + '-' + str(datevalue[1])
+ '-' + str(datevalue[2])
+ ' | ' + "Prize: " + jackpotvalue
+ ' | ' + "Jackpot Winner(s)"]
result.append(historylabel)
# print(result)
# print(type(result))
# print(datevalue)
# print(jackpotvalue)
# print(outcome)
# print(historylabel)
for obj in result:
# print("Here is an obj in item")
self.outputlabel = QLabel(self)
self.labeltext = QLabel(self)
self.labeltext.setText(str(obj))
self.labeltext.setAlignment(QtCore.Qt.AlignCenter)
self.labeltext.setStyleSheet("QLabel { color : black; }")
self.labeltext.setFont(QFont("Arial", 18))
if i < 6:
self.pixmap = QPixmap(u":/graphics/whiteball.png")
elif i == 6:
self.pixmap = QPixmap(u":/graphics/redball.png")
self.outputlabel.setPixmap(self.pixmap)
self.outputlabel.setScaledContents(Qt.KeepAspectRatio)
# self.outputlabel.resize(self.pixmap.width(),
# self.pixmap.height())
self.outputlabel.setMinimumSize(112, 112)
self.labeltext.setMinimumSize(56, 56)
self.outputlabel.setMaximumSize(112, 112)
self.labeltext.setMaximumSize(800, 800)
self.gridlayout.addWidget(self.outputlabel, ballrow, ballcolumn, 1, 1)
self.gridlayout.addWidget(self.labeltext, ballrow, ballcolumn, 1, 1)
# self.groupbox.setLayout(self.gridlayout)
# self.scroll.setLayout(self.gridlayout)
i += 1
ballcolumn += 1
if i == 7:
i += 1
inforow += 1
elif i > 7:
self.outputlabel.setPixmap(None)
self.labeltext.setText(" " + str(historylabel[0]))
self.labeltext.setStyleSheet("QLabel { color : #7393B3; }") #steel blue 4682B4 bright blue 0096FF denim 6F8FAF royal blue 4169E1 blue gray 7393B3
self.labeltext.setFont(QFont("Arial", 18))
self.labeltext.setAlignment(Qt.AlignmentFlag.AlignLeft)
self.gridlayout.addWidget(self.labeltext, inforow, infocolumn, 1, 10)
i = 1
inforow += 2
ballrow += 3
ballcolumn = 0
# widget is parent widget of grid layout. being added to scroll layout
self.scroll.setWidget(self.widget)
self.setCentralWidget(self.scroll)
# resize entire window show to display all objects (width, height)
# self.resize(1000, 550)
self.show()
else:
x = 265
y = 225
w = 275
h = 100
self.labeltext = QLabel(self)
self.labeltext.setText("Sorry, no results to display. Please try again.")
self.labeltext.setStyleSheet("QLabel { color : white; }")
self.labeltext.setGeometry(x, y, w, h)
self.show()
My props to SimoN SavioR for helping me out with their greater understanding of layouts; couldn't have figured out a final solution without their contribution!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | SimoN SavioR |
| Solution 2 | embersofadyingfire |




