Why PlotWidget does't scale in GridLayout cell? - python

I put some widgets in a grid. But all the time there is a strange behavior of these widgets.
If you put one ImageView and PlotWidget near, ImageView cringe and PlotWidged stretched. I put near two ImageView and two PlotWidget to check - everything works fine. What's wrong?
import sys
import numpy as np
from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QApplication
import pyqtgraph as pg
from PIL import Image
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
self.Imv = pg.ImageView()
win = pg.PlotWidget()
win.plot(np.random.random_sample(40)*10)
btn1 = QPushButton("Start")
btn2 = QPushButton('Forward/backward')
btn3 = QPushButton('Filters')
grid.addWidget(self.Imv, 0, 0, 1, 1)
grid.addWidget(win, 0, 1, 1, 1)
grid.addWidget(btn1, 1, 0, 1, 1)
grid.addWidget(btn2, 2, 0, 1, 1)
grid.addWidget(btn3, 3, 0, 1, 1)
btn1.clicked.connect(self.cap)
self.move(300, 150)
self.setWindowTitle('Scentific camera view')
self.show()
def cap(self):
global Imv
img = np.array(Image.open('D:/Frames/image7.jpg'))
self.Imv.setImage(img.T)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
So it looks:
Two ImageView near - it's fine:

I would recomend to build your UI with QTDesigner and autogenerate the code. That makes things much easier. If you have to do it by hand try to set size policy to expanding or change the geometry to a fixed size:
win.setGeometry(QtCore.QRect(10, 20, 621, 181))
win.setSizePolicy(QtWidgets.QSizePolicy.Expanding)

Related

PQYT Make QGridLayout scrollable

I was wondering if it is possible to add a QScrollArea to a QGridLayout? Below is my attempt however, it always fails with the error.
TypeError: setWidget(self, QWidget): argument 1 has unexpected type 'QGridLayout'
Is this method only possible for combo and list boxes? I am basically passing QPixmap images into a QGridLayout which needs to be scrolled. Any help much appreciated thank you.
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class PicClip(QWidget):
def __init__(self):
super().__init__()
# Load image
self.im = QPixmap("1.jpg")
self.im1 = QPixmap("1.jpg")
# Label 1
self.label = QLabel()
self.label.setPixmap(self.im)
# Label 2
self.label1 = QLabel()
self.label1.setPixmap(self.im1)
# Make Grid
self.grid = QGridLayout()
# Create widgets to grid
self.grid.addWidget(self.label, 0, 1, alignment=Qt.AlignCenter)
self.grid.addWidget(self.label1, 1, 1, alignment=Qt.AlignCenter)
# Set layout of Grid
self.setLayout(self.grid)
# Scroll
scroll = QScrollArea()
scroll.setWidget(self.grid)
scroll.setWidgetResizable(True)
# Show
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = PicClip()
sys.exit(app.exec_())
self.grid is layout and you are trying to add layout using setWidget function. setWidget function only gets QWidget
simple trick is to add wrapper QWidget and set self.grid as its layout
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class PicClip(QMainWindow): # I modified this line to show window properly
def __init__(self):
super().__init__()
# Load image
self.im = QPixmap("1.jpg")
self.im1 = QPixmap("1.jpg")
# Label 1
self.label = QLabel()
self.label.setPixmap(self.im)
# Label 2
self.label1 = QLabel()
self.label1.setPixmap(self.im1)
# Make Grid
self.grid = QGridLayout()
# Create widgets to grid
self.grid.addWidget(self.label, 0, 1, alignment=Qt.AlignCenter)
self.grid.addWidget(self.label1, 1, 1, alignment=Qt.AlignCenter)
# Set layout of Grid
self.setLayout(self.grid)
# Scroll
scroll = QScrollArea()
# add wrapper widget and set its layout
wrapper_widget = QWidget()
wrapper_widget.setLayout(self.grid)
scroll.setWidget(wrapper_widget)
scroll.setWidgetResizable(True)
# Show
self.setCentralWidget(scroll) # I modified this line to show window properly
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = PicClip()
sys.exit(app.exec_())

How to modify/clear/delete a QWidget from a QGridLayout ? - Python, PyQt

I wish to have a QGridLayout containing some informations that can be dynamicaaly changed. However, as it is, it will only superimpose the different informations on top of the previous one instead of replacing it. Surprisingly I couldn't find a method to remove or clean or such a widget from a grid. So what, can't it be dynamically changed ?...
Here is an example of code :
import sys
from PyQt5.QtWidgets import (
QApplication,
QGridLayout,
QPushButton,
QWidget,
QLabel
)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QGridLayout Example")
# Create a QGridLayout instance
self.buttonA = QPushButton("A")
self.buttonB = QPushButton("B")
self.layout = QGridLayout()
# Add widgets to the layout
self.layout.addWidget(self.buttonA, 0, 1)
self.layout.addWidget(self.buttonB, 0, 2)
self.layout.addWidget(QPushButton("C"), 1, 0)
self.layout.addWidget(QPushButton("D"), 1, 1)
self.layout.addWidget(QPushButton("E"), 1, 2)
self.layout.addWidget(QPushButton("F"), 2, 0)
self.layout.addWidget(QPushButton("G"), 2, 1)
self.layout.addWidget(QPushButton("H"), 2, 2)
# Set the layout on the application's window
self.setLayout(self.layout)
self.buttonA.clicked.connect(self.change_label)
self.buttonB.clicked.connect(self.change_label2)
def change_label(self):
self.label = QLabel("Hello")
self.layout.addWidget(self.label, 0, 0)
def change_label2(self):
self.label = QLabel("Bonjour")
self.layout.addWidget(self.label, 0, 0)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
When one clicks on button A, I want to have displayed in box (0,0) "Hello". Then if one clicks on button B, I want to replace the text "Hello" with "Bonjour". However I can only have one text on top of the other which is obviously hardly readable then.
Can someone help me ?
Just use this code:
import sys
from PyQt5.QtWidgets import (
QApplication,
QGridLayout,
QPushButton,
QWidget,
QLabel
)
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QGridLayout Example")
# Create a QGridLayout instance
self.label = QLabel("Show text here")
self.buttonA = QPushButton("A")
self.buttonB = QPushButton("B")
self.layout = QGridLayout()
# Add widgets to the layout
self.layout.addWidget(self.label, 0, 0)
self.layout.addWidget(self.buttonA, 0, 1)
self.layout.addWidget(self.buttonB, 0, 2)
self.layout.addWidget(QPushButton("C"), 1, 0)
self.layout.addWidget(QPushButton("D"), 1, 1)
self.layout.addWidget(QPushButton("E"), 1, 2)
self.layout.addWidget(QPushButton("F"), 2, 0)
self.layout.addWidget(QPushButton("G"), 2, 1)
self.layout.addWidget(QPushButton("H"), 2, 2)
# Set the layout on the application's window
self.setLayout(self.layout)
self.buttonA.clicked.connect(self.change_label)
self.buttonB.clicked.connect(self.change_label2)
def change_label(self):
self.label.setText("Hello")
def change_label2(self):
self.label.setText("Bonjour")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

how to let the layout showed in the bottom

The window would have two layouts: A, the main layout to show some images; B, the qlabel to show some status. When the window is started, A would be empty. A would show some images after some operations.
My question is: how to let B show in the bottom? The current code is:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class TimeLine(QMainWindow):
def __init__(self):
super(TimeLine, self).__init__()
widget = QWidget()
self.setCentralWidget(widget)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
widget.setLayout(layout)
statusLabel = QLabel('status bar')
statusLabel.setStyleSheet("background-color:blue")
statusLabel.setMaximumHeight(20)
layout.addWidget(statusLabel)
layout.setSpacing(0)
app = QApplication(sys.argv)
window = TimeLine()
window.show()
app.exec_()
And the result is:
The blue label shows in the middle, and I want it to be show in the bottom.
Then, I add a stretch. The layout B would show in the bottom, however, the layout A would also be squeezed. The code is:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class TimeLine(QMainWindow):
def __init__(self):
super(TimeLine, self).__init__()
widget = QWidget()
self.setCentralWidget(widget)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
widget.setLayout(layout)
mainLabel = QLabel()
mainLabel.setStyleSheet("background-color:yellow")
statusLabel = QLabel()
statusLabel.setStyleSheet("background-color:blue")
statusLabel.setMaximumHeight(20)
layout.addWidget(mainLabel)
layout.addStretch()
layout.addWidget(statusLabel)
layout.setSpacing(0)
app = QApplication(sys.argv)
window = TimeLine()
window.show()
app.exec_()
And the result is:
The yellow label is the main label, the gray color represents the back ground. I want the yellow label to occupy all the window except from the blue label.
Thus, what I want is:
when there is no other label, I hope the blue label show in the bottom, like:
where there is another label (yellow label), I hope the yellow label occupy all the space except from the blue label, like:
I saw your task like this:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class TimeLine(QMainWindow):
def __init__(self):
super(TimeLine, self).__init__()
widget = QWidget()
self.setCentralWidget(widget)
mainLabel = QLabel("This is a label.", alignment = Qt.AlignCenter)
mainLabel.setStyleSheet("background-color:yellow")
layout = QVBoxLayout(widget)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(mainLabel)
self.statusBar().setStyleSheet("background-color:blue; color: #fff")
self.statusBar().showMessage('Hello {} !'.format('status bar'))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = TimeLine()
window.show()
sys.exit(app.exec_())
If I understand your question correctly, you want the blue label to be aligned with the bottom edge of the main window at all times. One way to get what you want to to set the alignment of the label to Qt.AlignBottom when adding it to the layout. You also need to adjust the stretch factors of the two labels to make sure the yellow label takes up all the space above the blue label when it's present, i.e.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
class TimeLine(QMainWindow):
def __init__(self):
super(TimeLine, self).__init__()
widget = QWidget()
self.setCentralWidget(widget)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
widget.setLayout(layout)
mainLabel = QLabel()
mainLabel.setStyleSheet("background-color:yellow")
statusLabel = QLabel('status bar')
statusLabel.setStyleSheet("background-color:blue")
statusLabel.setMaximumHeight(20)
layout.addWidget(mainLabel, stretch = 1)
layout.addWidget(statusLabel, stretch = 0, alignment = Qt.AlignBottom)
layout.setSpacing(0)
app = QApplication(sys.argv)
window = TimeLine()
window.show()
app.exec_()
Both labels:
Blue label only:

Align QLCDNumber text to right

I have QGridLayout in which I insert QLCDNumber as follows:
self.mainLayout.addWidget(display, 0, 0, 1 , 5)
Everything is quite fine but the digit (0 by default) is 'moving' from center to right while window scaling. Can someone give me a hint how to prevent QLCDNumber from scalling and to align text inside it to the right?
Try it:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Window(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.lcd = QLCDNumber()
self.lcd.setFixedSize(150, 70) # Set the size you want
self.lcd.display(12345)
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.mainLayout = QGridLayout(centralWidget)
self.mainLayout.addWidget(self.lcd, 0, 0, Qt.AlignRight) # Set the alignment option
self.mainLayout.addWidget(QTextEdit("TextEdit..."), 1,0)
self.mainLayout.addWidget(QPushButton("Button"), 2,0, Qt.AlignCenter)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Window()
ex.show()
sys.exit(app.exec_())

How to overlay widgets in PyQt5?

I would like to render some layouts - that groups some widgets - over a background layout that contains an image widget.
Let me explain myself with an image. The following image shows the desired output:
However, all I haven't find the way to overlay the two image widgets, and they show like this:
And this is the Python code I wrote:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5 import QtCore, Qt
import sys
class ExampleWindow(QMainWindow):
def __init__(self, windowsize):
super().__init__()
self.windowsize = windowsize
self.initUI()
def initUI(self):
self.setGeometry(0, 0, self.windowsize.width(), self.windowsize.height())
self.setMaximumSize(self.windowsize.width(), self.windowsize.height())
self.setMinimumSize(self.windowsize.width(), self.windowsize.height())
self.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint)
widget = QWidget()
self.setCentralWidget(widget)
# Picture 1's widget
pixmap = QPixmap('picture_1.jpg')
pixmap = pixmap.scaledToWidth(self.windowsize.width())
self.image = QLabel()
self.image.setPixmap(pixmap)
left_box = QVBoxLayout()
left_box.setContentsMargins(0,0,0,0)
left_box.setSpacing(0)
left_box.setAlignment(Qt.Qt.AlignLeft)
left_box.addWidget(self.image, 0, Qt.Qt.AlignLeft | Qt.Qt.AlignTop)
# Picture 2's widget
pixmap = QPixmap('picture_2.jpg')
pixmap = pixmap.scaledToWidth(400)
self.image2 = QLabel()
self.image2.setPixmap(pixmap)
right_box = QVBoxLayout()
right_box.setContentsMargins(0, 0, 0, 0)
right_box.setSpacing(0)
right_box.setAlignment(Qt.Qt.AlignLeft)
right_box.addWidget(self.image2, 0, Qt.Qt.AlignLeft | Qt.Qt.AlignBottom)
layout_box = QHBoxLayout()
layout_box.addLayout(left_box)
layout_box.addLayout(right_box)
widget.setLayout(layout_box)
if __name__ == '__main__':
app = QApplication(sys.argv)
screensize = app.desktop().availableGeometry()
ex = ExampleWindow(screensize)
ex.show()
sys.exit(app.exec_())
Could you please help me to modify my code in order to get the widgets overlaid as shown on first image?
Layouts are elements that manage the geometry of widgets, in your case both layouts try to occupy the largest available space. For a widget to be part of another widget there are 2 possibilities, the first is to use a layout, and the second is that the main widget is the father of the new widget, in the case of the first image we will use the first one, and for the second one we will use the second method.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class ExampleWindow(QMainWindow):
def __init__(self, windowsize):
super().__init__()
self.windowsize = windowsize
self.initUI()
def initUI(self):
self.setFixedSize(self.windowsize)
self.setWindowFlags(Qt.CustomizeWindowHint | Qt.FramelessWindowHint)
widget = QWidget()
self.setCentralWidget(widget)
pixmap1 = QPixmap('picture_1.jpg')
pixmap1 = pixmap1.scaledToWidth(self.windowsize.width())
self.image = QLabel()
self.image.setPixmap(pixmap1)
layout_box = QHBoxLayout(widget)
layout_box.setContentsMargins(0, 0, 0, 0)
layout_box.addWidget(self.image)
pixmap2 = QPixmap('picture_2.jpg')
self.image2 = QLabel(widget)
self.image2.setPixmap(pixmap2)
self.image2.setFixedSize(pixmap2.size())
p = self.geometry().bottomRight() - self.image2.geometry().bottomRight() - QPoint(100, 100)
self.image2.move(p)
if __name__ == '__main__':
app = QApplication(sys.argv)
screensize = app.desktop().availableGeometry().size()
ex = ExampleWindow(screensize)
ex.show()
sys.exit(app.exec_())

Categories