Python Forum
[PyQt] How do I get a QScrollArea to scroll?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] How do I get a QScrollArea to scroll?
#1
A lot of people seem to have this problem. How do I get a QScrollArea to scroll. I have this code below that creates widgets and places them in lines in a QScrollArea to display information. I need to set 4 widgest per line and space them out properly to display all the needed information. The problem in I cant get the ScrollArea to scroll.

(Using PyQt5)

self.pkg_display = QtWidgets.QScrollArea(self)
self.pkg_display.setGeometry(10, 40, 801, 401)
self.pkg_display.setStyleSheet("background-color: White")
self.pkg_display.setVerticalScrollBarPolicy(2)
self.pkg_display.setWidgetResizable(True)
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(0, 0, 801, 800)
self.pkg_display.setWidget(self.scrollAreaWidgetContents)
def update_list():
    pos = 0
    x1 = 10
    y1 = 2
    x2 = 393
    y2 = 5
    x3 = 700
    x4 = 756
    for i in filtered_name:
        cb = QtWidgets.QCheckBox(ui.scrollAreaWidgetContents)
        cb.setGeometry(x1,y1,361,23)
        cb.setText(i)
        vtext = QtWidgets.QLabel(ui.scrollAreaWidgetContents)
        vtext.setGeometry(x2,y2,291,17)
        vtext.setText(filtered_version[pos])
        stext = QtWidgets.QLabel(ui.scrollAreaWidgetContents)
        stext.setGeometry(x3,y2,51,17)
        stext.setText(filtered_size[pos])
        ib = QtWidgets.QPushButton(ui.scrollAreaWidgetContents)
        ib.setGeometry(x4,y1,21,21)
        ib.setText("i")
        y1 += 23
        y2 += 23
        pos += 1
    ui.pkg_display.update()
The code creates the widjets and places them in the ScrollArea(pkg_dsiplay), but it will not scroll.
If anyone is wondering I am working on a tool to replace dnfdrogora(A Linux graphical package manager tool)
Reply
#2
Nobody can really help with a few snippets of code.

Example PyQt5 GUI Creating QScrollArea
Reply
#3
(Oct-22-2021, 08:08 PM)Axel_Erfurt Wrote: Nobody can really help with a few snippets of code.

Example PyQt5 GUI Creating QScrollArea

Here is a full example of how I am creating the the window, scrollarea, and widgets.
import sys
import subprocess
from PyQt5 import QtWidgets

filtered_name = []
filtered_version = []
filtered_size = []
app = QtWidgets.QApplication(sys.argv)

class MyWindow(QtWidgets.QMainWindow):
    def setup(self):
        QtWidgets.QMainWindow.__init__(self)
        self.resize(820, 625)
        self.setWindowTitle("PkgMgr")
        self.setMaximumSize(820, 620)
        self.setMinimumSize(16, 9)

        self.uninstallB = QtWidgets.QPushButton(self)
        self.uninstallB.setGeometry(10, 10, 111, 25)
        self.uninstallB.setText("Uninstall")

        self.clear_selectB = QtWidgets.QPushButton(self)
        self.clear_selectB.setGeometry(130, 10, 111, 25)
        self.clear_selectB.setText("Clear Selection")

        self.searchB = QtWidgets.QPushButton(self)
        self.searchB.setGeometry(620, 10, 91, 25)
        self.searchB.setText("Search")

        self.clear_searchB = QtWidgets.QPushButton(self)
        self.clear_searchB.setGeometry(720, 10, 91, 25)
        self.clear_searchB.setText("Clear Search")

        self.search_bar = QtWidgets.QLineEdit(self)
        self.search_bar.setGeometry(450, 10, 161, 25)

        self.pkg_display = QtWidgets.QScrollArea(self)
        self.pkg_display.setGeometry(10, 40, 801, 401)
        self.pkg_display.setStyleSheet("background-color: White")
        self.pkg_display.setVerticalScrollBarPolicy(2)
        self.pkg_display.setWidgetResizable(True)
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setGeometry(0, 0, 801, 800)
        self.pkg_display.setWidget(self.scrollAreaWidgetContents)

        self.info_display = QtWidgets.QTextBrowser(self)
        self.info_display.setGeometry(10, 450, 801, 161)

def get_package(mode):
    cmd = subprocess.Popen("dnf info -C --installed", shell=True, stdout=subprocess.PIPE)
    raw_out = cmd.stdout.readlines()
    vpos = 0
    for l in raw_out:
        l = str(l)
        size = l.find("b'Size")
        name = l.find("b'Name")
        version = l.find("b'Version")
        release = l.find("b'Release")
        if name != -1:
            line = l[name+17:len(l)-3]
            filtered_name.append(line)
        elif version != -1:
            line = l[version+17:len(l)-3]
            filtered_version.append(line)
        elif release != -1:
            line = l[release+17:len(l)-3]
            filtered_version[vpos] += "-" + line
            vpos += 1
        elif size != -1:
            line = l[size+17:len(l)-3]
            filtered_size.append(line)

def update_list():
    pos = 0
    x1 = 10
    y1 = 2
    x2 = 393
    y2 = 5
    x3 = 700
    x4 = 756
    for l in filtered_name:
        cb = QtWidgets.QCheckBox(ui.scrollAreaWidgetContents)
        cb.setGeometry(x1,y1,361,23)
        cb.setText(l)
        vtext = QtWidgets.QLabel(ui.scrollAreaWidgetContents)
        vtext.setGeometry(x2,y2,291,17)
        vtext.setText(filtered_version[pos])
        stext = QtWidgets.QLabel(ui.scrollAreaWidgetContents)
        stext.setGeometry(x3,y2,51,17)
        stext.setText(filtered_size[pos])
        ib = QtWidgets.QPushButton(ui.scrollAreaWidgetContents)
        ib.setGeometry(x4,y1,21,21)
        ib.setText("i")
        y1 += 23
        y2 += 23
        pos += 1
    ui.pkg_display.update()
    
ui = MyWindow()
ui.setup()
get_package(0)
update_list()
ui.show()
sys.exit(app.exec_())
Reply
#4
I cannot run your example (I have PySide2) and translating to PySide2 is difficult because of how you use the designer (which I hate hate hate hate designer code).

This is a short example of a working scrollable area.
import sys
import PySide2.QtWidgets as QtWidgets
from PySide2.QtCore import Qt

class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.view = QtWidgets.QWidget()
        self.layout = QtWidgets.QVBoxLayout(self.view)
        self.scroll = QtWidgets.QScrollArea(self)
        self.scroll.setWidgetResizable(True)
        self.scroll.setWidget(self.view)
        self.setCentralWidget(self.scroll)
        for i in range(20):
            self.layout.addWidget(QtWidgets.QLabel('Make this a fairly wide Label '+str(i)))
     
app = QtWidgets.QApplication(sys.argv)
ui = MyWindow()
ui.show()
sys.exit(app.exec_())
The important parts are that the scrolled widget is larger than the scrollable area and that the scrollable area knows how big the scrolled widget is (setWidgetResizeable(True)).

Looking at your example I think the problem is that the scrolled widget is not larger than the scrollable area. I'm guessing that ui.scrollAreaWidgetContents is your scrolled widget (a QWidget?). I see where you place things in this widget but I don't see where the widget is resized. I would stop using setGeometry and use a layout manager instead. That will automatically grow the scrolled widget as needed.
Reply
#5
Why don't you just use a QTableWidget with checkboxes?

Here is a simple example (for apt, since I use mint)

[Image: test55.png?raw=1]

import sys
import subprocess
from PyQt5 import QtWidgets, QtCore
 
filtered_name = []
filtered_version = []
filtered_size = []
app = QtWidgets.QApplication(sys.argv)
 
class MyWindow(QtWidgets.QMainWindow):
    def setup(self):
        QtWidgets.QMainWindow.__init__(self)
        self.resize(820, 625)
        self.setWindowTitle("PkgMgr")
        self.setMaximumSize(820, 620)
        self.setMinimumSize(16, 9)
 
        self.table = QtWidgets.QTableWidget()
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(["", "Name", "Version"])
        self.setCentralWidget(self.table)
 
    def get_package(self, mode):
        cmd = subprocess.Popen("apt list --installed", shell=True, stdout=subprocess.PIPE)
        raw_out = cmd.stdout.readlines()
        for l in raw_out[1:]:
            name = l.decode().partition("/")[0]
            version = l.decode().partition("/")[2].partition(",now ")[2]
            print(name, version)
            filtered_name.append(name)
            filtered_version.append(version)
 
    def update_list(self):
        for x in range(len(filtered_name)):
            self.table.insertRow(x)
            item = QtWidgets.QTableWidgetItem('uninstall')
            item.setFlags(QtCore.Qt.ItemIsUserCheckable |
                                  QtCore.Qt.ItemIsEnabled)
            item.setCheckState(QtCore.Qt.Unchecked)
            self.table.setItem(x, 0, item)            
            self.table.setItem(x, 1, QtWidgets.QTableWidgetItem(filtered_name[x]))
            self.table.setItem(x, 2, QtWidgets.QTableWidgetItem(filtered_version[x]))
        self.table.resizeColumnsToContents()

     
ui = MyWindow()
ui.setup()
ui.get_package(0)
ui.update_list()
ui.show()
sys.exit(app.exec_())
Reply
#6
"The important parts are that the scrolled widget is larger than the scrollable area and that the scrollable area knows how big the scrolled widget is (setWidgetResizeable(True))."

But when I do self.scrollAreaWidgetContents.setGeometry(0, 0, 801, 800) or self.scrollAreaWidgetContents.resize(801,800) is that not making it larger than pkg_display(self.pkg_display.setGeometry(10, 40, 801, 401)? The problem I have with layout managers is I can't control where my widgets are placed or how big/small they are.

@Axel_Erfurt
Yes I could do that, but this the effect that I wanted to achieve.
   

EDIT: So I just removed self.pkg_display.setWidgetResizable(True) from my code... and now my scroll area works just fine.
Reply
#7
Using setGeometry is not a good idea. A BoxLayout (HBox, VBox) or GridLayout is better.
Reply
#8
I agree that setGeometry is a bad idea. Your example is easily achieved using a grid layout manager.
Reply
#9
(Oct-26-2021, 08:05 PM)deanhystad Wrote: I agree that setGeometry is a bad idea. Your example is easily achieved using a grid layout manager.

Then could you please give me an example? I don't know how to use layout managers.
Reply
#10
Layouts

all examples
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Treeview scroll selected node to top rfresh737 1 711 Apr-14-2021, 03:27 AM
Last Post: deanhystad
  [Tkinter] canvas widget scroll issue chrisdb 2 977 Apr-07-2021, 05:48 AM
Last Post: chrisdb
  [Tkinter] Help with scroll bars kraco 1 1,146 Sep-27-2020, 11:20 PM
Last Post: Larz60+
  [Tkinter] How to place scroll bar correctly scratchmyhead 1 1,731 May-18-2020, 04:17 PM
Last Post: scratchmyhead
  Scroll frame with MouseWheel Nemesis 1 1,081 Mar-25-2020, 09:29 PM
Last Post: Nemesis
  [Kivy] Why I have to click twice to scroll? Hummingbird 0 1,418 Jan-06-2020, 09:08 PM
Last Post: Hummingbird
  [Tkinter] Scroll Bars going backwards goofygoo 2 1,325 Jun-07-2019, 05:07 PM
Last Post: goofygoo
  [PyQt] QScrollArea with a gridlayout littleGreenDude 2 5,919 Jan-28-2019, 07:14 PM
Last Post: littleGreenDude
  [Tkinter] Scroll at cursor position lollo 4 3,994 Jan-31-2018, 11:33 PM
Last Post: lollo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020