pyqt5 QScrollArea inheritance - python

I'm having a hard time understanding how to use scroll bars in PyQt5. I have an arbitrary layout to experiment with, which is just some blocks of colors. I'd like to have the layout of colors to have a minimum size, and when the window is smaller than that, the scroll bars appear (or the scroll bars are just present all the time). I found this example:
PyQt: Put scrollbars in this
and changed it to work with PyQt5:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QScrollArea, QVBoxLayout, QWidget
class myDialog(QDialog):
_buttons = 0
def __init__(self, parent=None):
super(myDialog, self).__init__(parent)
self.pushButton = QPushButton(self)
self.pushButton.setText("Add Button!")
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget(self.scrollArea)
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 380, 247))
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.verticalLayout = QVBoxLayout(self)
self.verticalLayout.addWidget(self.pushButton)
self.verticalLayout.addWidget(self.scrollArea)
self.verticalLayoutScroll = QVBoxLayout(self.scrollAreaWidgetContents)
'''
verticalLayoutScroll is a child of scrollAreaWidgetContents
scrollAreaWidgetContents is a child of scrollArea
scrollArea is child of self
verticalLayout is also a child of self has the widgets pushButton and scrollArea
'''
#QtCore.pyqtSlot()
def on_pushButton_clicked(self):
self._buttons += 1
pustButtonName = u"Button {0}".format(self._buttons)
pushButton = QPushButton(self.scrollAreaWidgetContents)
pushButton.setText(pustButtonName)
self.verticalLayoutScroll.addWidget(pushButton)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
app.setApplicationName('myDialog')
main = myDialog()
main.show()
sys.exit(app.exec_())
Here is my code:
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 15 07:37:28 2018
#author: Erik
"""
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QSlider, QPushButton,
QMainWindow, QAction, qApp,
QLCDNumber, QGridLayout, QLabel, QLineEdit, QVBoxLayout, QHBoxLayout,
QSizePolicy, QScrollArea, QLayout)
from PyQt5.QtGui import QIcon, QColor, QPalette
from PyQt5.QtCore import Qt, QSize, QRect
class Color(QWidget):
def __init__(self, color, *args, **kwargs):
super(Color, self).__init__(*args, **kwargs)
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.Window, QColor(color))
self.setPalette(palette)
class Color2(QWidget):
def __init__(self, color, *args, **kwargs):
super(Color2, self).__init__(*args, **kwargs)
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.Window, QColor(color))
self.setPalette(palette)
def sizeHint(self):
return QSize(150,150)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("My Awesome App")
size = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
layout = QVBoxLayout()
layout2 = QVBoxLayout()
brw = Color2('brown')
brw.setSizePolicy(size)
layout2.addWidget(brw)
layout2.addWidget(Color('black'))
layout2.setStretch(1,2)
layout2.addWidget(Color('cyan'))
layout2.setStretch(2, 1)
layout.addWidget(Color('red'))
layout.addWidget(Color('blue'))
layout.addWidget(Color('green'))
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget(self.scrollArea)
self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 600, 500))
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.scrollAreaWidgetContents.setMinimumSize(QSize(500, 500))
self.scrollLayout = QVBoxLayout(self.scrollAreaWidgetContents)
#self.scrollLayout.setSizeConstraint(QLayout.SetMinimumSize) #2
self.mainLayout = QHBoxLayout()
self.mainLayout.addWidget(Color('purple'))
self.mainLayout.addWidget(Color('yellow'))
self.mainLayout.addWidget(Color('orange'))
self.mainLayout.addLayout(layout2)
self.mainLayout.addLayout(layout)
self.scrollLayout.addLayout(self.mainLayout)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
I can barely see the colors in the scrollArea. In the first code block above, I don't understand the necessary inheritance structure I described in the comment block. Do I need to extend a layout class to set a minimum size?
https://doc.qt.io/qt-5/qlayoutitem.html#minimumSize
How is the "Size Hints and Layouts" section of https://doc.qt.io/qt-5/qscrollarea.html#details relevant?
Thanks.

The problem is that you have not established the QScrollArea as centralWidget.
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("My Awesome App")
size = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
layout = QVBoxLayout()
layout2 = QVBoxLayout()
brw = Color2('brown')
brw.setSizePolicy(size)
layout2.addWidget(brw)
layout2.addWidget(Color('black'))
layout2.setStretch(1,2)
layout2.addWidget(Color('cyan'))
layout2.setStretch(2, 1)
layout.addWidget(Color('red'))
layout.addWidget(Color('blue'))
layout.addWidget(Color('green'))
self.scrollArea = QScrollArea()
# set CentralWidget
self.setCentralWidget(self.scrollArea)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget(self.scrollArea)
self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 600, 500))
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.scrollAreaWidgetContents.setMinimumSize(QSize(500, 500))
self.scrollLayout = QVBoxLayout(self.scrollAreaWidgetContents)
#self.scrollLayout.setSizeConstraint(QLayout.SetMinimumSize) #2
self.mainLayout = QHBoxLayout()
self.mainLayout.addWidget(Color('purple'))
self.mainLayout.addWidget(Color('yellow'))
self.mainLayout.addWidget(Color('orange'))
self.mainLayout.addLayout(layout2)
self.mainLayout.addLayout(layout)
self.scrollLayout.addLayout(self.mainLayout)
self.show()

Related

How can I generate the buttons and connect them to different functions? [duplicate]

This question already has answers here:
How do I assert the identity of a PyQt5 signal?
(2 answers)
Closed 2 years ago.
I've created a search engine in PyQt5, using the code below:
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super(Label, self).__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def show(self):
for labels in [self, self.lbl]:
labels.setVisible(True)
def hide(self):
for labels in [self, self.lbl]:
labels.setVisible(False)
def printsignal(self):
print("clicked")
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The problem I have is, all the buttons share the same function and I don't know how to make them have different signals, as they are generated automatically. Basically, if I run the code it will show up like
this:
and when I press any of the buttons, it will print "clicked" (as in printsignal function). What I want is a different function for each button. Is there a way to do that?
Normally you can use self.sender().text() to get text from QButton which generated signal.
But because you create own widget Label with QButton and QLabel and you want text from label so you can get directly self.name
def printsignal(self):
print("clicked", self.name)
eventually self.lbl.text()
def printsignal(self):
print("clicked", self.lbl.text())
Working code.
I removed show(), hide() because you don't need it
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super().__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def printsignal(self):
print("clicked", self.name)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Pyqt5 QLabel with image at top and text at bottom

I am trying to create a PyQt5 - QLabel with both image and text. I would like to have a text at the bottom of the image. Below is a part of the code
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
l4=QLabel()
l4.setText('delete')
l4.setAlignment(Qt.AlignBottom)
pixmap = QPixmap("/home/moh/Documents/My_GUI/Icons/Delete.png")
l4.setPixmap(pixmap)
l4.setAlignment(Qt.AlignTop)
self.layout = QGridLayout()
self.layout.addWidget(l4, 0, 0)
self.setLayout(self.layout)
self.show()
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
You have to use 2 QLabel in a QVBoxLayout:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
pixmap_label = QLabel(
pixmap=QPixmap("/home/moh/Documents/My_GUI/Icons/Delete.png")
)
text_label = QLabel(text="delete")
lay = QVBoxLayout(self)
lay.addWidget(pixmap_label, alignment=Qt.AlignCenter)
lay.addWidget(text_label, alignment=Qt.AlignCenter)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
If you want to use a circle Qlabel image, use this code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QPainterPath, QPainter
from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget
class Label(QLabel):
def __init__(self, *args, antialiasing=True, **kwargs):
super(Label, self).__init__(*args, **kwargs)
self.Antialiasing = antialiasing
self.setMaximumSize(90, 90)
self.setMinimumSize(90, 90)
self.radius = 45
self.target = QPixmap(self.size())
self.target.fill(Qt.transparent)
p = QPixmap("Image.jpg").scaled(
90, 90, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
painter = QPainter(self.target)
if self.Antialiasing:
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setRenderHint(QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
path = QPainterPath()
path.addRoundedRect(
0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(self.target)
class Window(QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
pixmap_label = Label()
text_label = QLabel(text="delete")
lay = QVBoxLayout(self)
lay.addWidget(pixmap_label, alignment=Qt.AlignCenter)
lay.addWidget(text_label, alignment=Qt.AlignCenter)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())

How to set window and it's graphicScene transparent(using slider) and leave only QPushButton visible

I want my window and it's QGraphicsScene to be transparent which is controlled by QSlider.
I tried looking for some answers here and there, but it's mainly setting background color to 0 :
self.setStyleSheet("background-color:rgba(0, 0, 0, 0);")
or like that :
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
Which does it job, but I would like to make slider which will control level of transparency and I don't see how can I do it with commands above.
Can somebody please give me some advise how to do it ? Thank you
I will attach my test code here below(I want to be able to control transparency of everything , but do not touch slider and button):
from PySide2.QtGui import QBrush, QColor
from PySide2.QtCore import QSize, Qt
from PySide2.QtWidgets import QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene, QFrame, QSizePolicy, QApplication, QSlider, QPushButton
class MainWindow(QDialog):
def __init__(self):
QDialog.__init__(self)
self.mainLayout = QVBoxLayout()
self.graphicsWidget = MainGraphicsWidget()
self.window = 'transp_test'
self.title = 'transparent UI'
self.size = (1000, 650)
self.create()
def create(self, **kwargs):
self.setWindowTitle(self.title)
self.resize(QSize(*self.size))
self.setLayout(self.mainLayout)
self.mainLayout.addWidget(self.graphicsWidget)
class MainGraphicsWidget(QGraphicsView):
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
self._scene = QGraphicsScene(backgroundBrush = Qt.gray)
self.setScene(self._scene)
self.transpSlider = QSlider()
self.transpSlider.setRange(0,100)
self.mainButton = QPushButton('I want it to be "Test" button')
self._scene.addWidget(self.mainButton)
self._scene.addWidget(self.transpSlider)
self.transpSlider.move(300, 100)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setBackgroundBrush(QBrush(QColor(30, 30, 30)))
self.setFrameShape(QFrame.NoFrame)
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(600, 300, 600, 600)
window.show()
sys.exit(app.exec_())
Here is one way.
class MainWindow(QDialog):
def __init__(self):
QDialog.__init__(self)
# these two lines are needed to get a transparent background in windows
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
# rest of class definition unchanged
class MainGraphicsWidget(QGraphicsView):
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
# set transparent background color for the widget itself
self.setStyleSheet("background-color: #00000000")
self._scene = QGraphicsScene()
self.setScene(self._scene)
# create of slider and connect to slot for changing opacity.
self.transpSlider = QSlider()
self.transpSlider.setStyleSheet('background-color: #00000000')
self.transpSlider.setRange(0,255)
self.transpSlider.valueChanged.connect(self.set_opacity)
self.transpSlider.setValue(255)
# rest of __init__ unchanged
def set_opacity(self, value):
brush = self.backgroundBrush()
color = brush.color()
color.setAlpha(value)
brush.setColor(color)
self.setBackgroundBrush(color)
Note that I've changed the range of the slider to 0-255 to make changing the opacity from fully opaque to fully transparent easier.
Try it:
#from PySide2.QtGui import QBrush, QColor
#from PySide2.QtCore import QSize, Qt
#from PySide2.QtWidgets import QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene, QFrame, QSizePolicy, QApplication, QSlider, QPushButton
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtGui import QBrush, QColor
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QGraphicsView, QGraphicsScene,
QFrame, QSizePolicy, QApplication, QSlider, QPushButton)
class MainGraphicsWidget(QGraphicsView):
def __init__(self, parent=None):
super(MainGraphicsWidget, self).__init__(parent)
self._scene = QGraphicsScene()
self.setScene(self._scene)
self.transpSlider = QtWidgets.QSlider(
QtCore.Qt.Horizontal,
minimum=10,
maximum=100,
value=100,
valueChanged=self.onValueChanged,
)
self.mainButton = QPushButton('I want it to be "Test" button \n QUIT')
self.mainButton.resize(150, 150)
self.mainButton.clicked.connect(parent.close)
self._scene.addWidget(self.mainButton)
self._scene.addWidget(self.transpSlider)
self.transpSlider.move(300, 100)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
c = QColor(220, 30, 30)
c.setAlphaF(1)
self.setBackgroundBrush(QBrush(c))
self.setFrameShape(QFrame.NoFrame)
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
#QtCore.pyqtSlot(int)
def onValueChanged(self, value):
c = QColor(220, 30, 30)
c.setAlphaF(value * 0.01)
self.setBackgroundBrush(QBrush(c))
window.setWindowOpacity(value * 0.03)
self.setStyleSheet("MainGraphicsWidget {{background-color: rgba(0, 215, 55, {});}}".format(value))
class MainWindow(QDialog):
def __init__(self):
super().__init__()
self.setAttribute(Qt.WA_NoSystemBackground, False)
self.setStyleSheet("MainWindow {background-color: rgba(0, 215, 55, 70);}")
self.graphicsWidget = MainGraphicsWidget(self)
self.window = 'transp_test'
self.title = 'transparent UI'
self.size = (1000, 650)
self.setWindowTitle(self.title)
self.resize(QSize(*self.size))
self.mainLayout = QVBoxLayout()
self.setLayout(self.mainLayout)
self.mainLayout.addWidget(self.graphicsWidget)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.setGeometry(600, 100, 600, 600)
window.show()
sys.exit(app.exec_())

Adding custom widgets to a QScrollArea in pyqt5 does not make scrollbar appear

The example shown below adds a very simple custom pyqt5 widget to a QScrollArea. When i move the custom widget "off" the area of the scroll area I would expect that scrollbars should appear. Obviously this is not the case.
#!/usr/bin/python3
from PyQt5.QtWidgets import QMainWindow, QWidget, QApplication, QScrollArea
from PyQt5.QtCore import QObject
from PyQt5.QtGui import QPainter, QColor, QPen
import sys
class ExampleWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
self.drawWidget(qp)
qp.end()
def drawWidget(self, qp):
qp.setPen(QColor(255, 0, 0))
qp.setBrush(QColor(255, 0, 0))
qp.drawRect(0, 0, 100, 100)
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 300, 200)
self.scrollArea = QScrollArea(self)
self.setCentralWidget(self.scrollArea)
self.widget = ExampleWidget(self.scrollArea)
self.widget.setGeometry(250, 150, 100, 100)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
How can I make the scrollbars appear once a widget is moved so it's not visible completely anymore?
In the code that samples ExampleWidget is a child of QScrollArea: self.widget = ExampleWidget(self.scrollArea), that does not imply that the widget is handled with the properties of the QScrollArea, the QScrollArea has a viewport() that is the background widget and the QScrollArea only shows a part of it. So if you want a widget to be inside you have to use the setWidget() method. On the other hand that viewport() has the size of the content and how it calculates that size ?, by default it uses the sizeHint() of the widget, and in your case it does not have it so it will not show what you want.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class ExampleWidget(QtWidgets.QWidget):
def paintEvent(self, e):
qp = QtGui.QPainter(self)
self.drawWidget(qp)
def drawWidget(self, qp):
qp.setPen(QtGui.QColor(255, 0, 0))
qp.setBrush(QtGui.QColor(255, 0, 0))
qp.drawRect(0, 0, 100, 100)
def sizeHint(self):
return QtCore.QSize(500, 500)
class Example(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.scrollArea = QtWidgets.QScrollArea()
self.setCentralWidget(self.scrollArea)
self.widget = ExampleWidget()
self.scrollArea.setWidget(self.widget)
self.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

Issue with QTextEdit, QPushButton one works with QMainWindow and the other with QWidget

Is there something in the QMainWindow class that won't allow to properly place a QPushButton where I want it to be?
Here the QPushButton "Quit" is at the wrong place and a little too big than usual.
My code is
import sys
from PyQt5.QtWidgets import (QApplication , QPushButton, QToolTip, QMessageBox, QMainWindow, QAction,
QHBoxLayout, QVBoxLayout, QWidget, QTextEdit)
from PyQt5.QtGui import QIcon, QFont
class QQtWidget(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn = QPushButton("Quit", self)
btn.clicked.connect(self.close)
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(btn)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.setGeometry(500, 500, 300, 150)
self.setWindowTitle("PyQt Test")
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
f = DemoQt()
sys.exit(app.exec())
If I make the class inherit from QWidget instead of QMainWindow the PushButton will be properly placed, but I can't use some other function if I inherit from QWidget.
Another Issue is with the QTextEdit module. It seems I cannot edit anything
in it if I use this code
class OpenSavePath(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.textEdit = QTextEdit()
"I realise here that this might be the problem as there is no
setCentralWidget() module in QWidget"""
#self.setCentralWidget(self.textEdit)
save_btn = QPushButton("Save", self)
save_btn.clicked.connect(self.saveCSV)
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(save_btn)
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setGeometry(300, 300, 300, 250)
self.setWindowTitle("Rocket Packet Preview")
Notice here the QPushbutton that is also misplaced. By changing the parent class QWidget with QMainWindow and adding this following line
self.setCentralWidget(self.textEdit)
The text editor issue is gone and I can edit. But then my QPushButton appears. Is there anyway to solve this?
For the first problem: You must use QSpacerItem to place it in a corner.
Example:
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QHBoxLayout, QSizePolicy, QSpacerItem, QPushButton
import sys
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
vbox = QVBoxLayout(self)
spacerItem = QSpacerItem(20, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)
vbox.addItem(spacerItem)
hbox = QHBoxLayout()
spacerItem1 = QSpacerItem(10, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
hbox.addItem(spacerItem1)
btn = QPushButton("Quit", self)
btn.clicked.connect(self.close)
hbox.addWidget(btn)
vbox.addLayout(hbox)
self.setGeometry(300, 300, 300, 250)
self.setWindowTitle("Rocket Packet Preview")
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec())
For this second problem: You must use QSpacerItem, QVBoxLayout, QHBoxLayout to organize the items. QMainWindow have loaded default widget like QStatusBar, QDockWidget, etc. So the setCentralWidget() function is used to place the main widget.
Example:
from PyQt5.QtWidgets import QWidget, QSpacerItem, QSizePolicy, QTextEdit, QApplication, QVBoxLayout, QHBoxLayout, QPushButton
import sys
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent=parent)
vbox = QVBoxLayout(self)
self.textEdit = QTextEdit(self)
vbox.addWidget(self.textEdit)
hbox = QHBoxLayout()
spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
hbox.addItem(spacerItem)
save_btn = QPushButton("Save", self)
hbox.addWidget(save_btn)
vbox.addLayout(hbox)
self.setGeometry(300, 300, 300, 250)
self.setWindowTitle("Rocket Packet Preview")
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec())

Categories