my function won't work when the slider value changed i don't know why ? it's my first time using PyQt5.
from PIL.ImageQt import Image, ImageQt
from PIL import ImageEnhance
from PyQt5.QtWidgets import (QApplication, QDialog, QGridLayout,
QLabel, QPushButton, QGroupBox,
QSlider, QVBoxLayout, QFileDialog)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QIcon
class MainWindow(QDialog):
def __init__(self):
super(MainWindow,self).__init__()
self.originalPalette = QApplication.palette()
# self.setAcceptDrops(True)
self.createTopGroupBox()
self.createBottomGroupBox()
# self.color("blue")
mainLayout = QGridLayout()
mainLayout.addWidget(self.topGroupBox, 0, 0)
mainLayout.addWidget(self.bottomGroupBox, 1, 0)
#mainLayout.setRowStretch(1, 1)
#mainLayout.setRowStretch(2, 1)
#mainLayout.setColumnStretch(0, 1)
#mainLayout.setColumnStretch(1, 1)
self.setLayout(mainLayout)
self.setWindowTitle("Photo Editor")
self.resize(800, 800)
def createTopGroupBox(self):
self.topGroupBox = QGroupBox()
openImgButton = QPushButton("Open Image")
openImgButton.clicked.connect(self.getImage)
self.label = QLabel("Your Photo")
layout = QVBoxLayout()
layout.addWidget(openImgButton)
layout.addWidget(self.label)
layout.addStretch(1)
self.topGroupBox.setLayout(layout)
def getImage(self):
global fname
fname = QFileDialog.getOpenFileName(self, 'Open file',
'c:\ ', "Image files (*.jpeg *.jpg *.gif *.bmp *.png))")
imagePath = fname[0]
#pixmap = QPixmap(imagePath)
self.image = Image.open(imagePath)
self.qimage = ImageQt(self.image)
self.label.setPixmap(QPixmap.fromImage(self.qimage))
self.resize(self.qimage.width(), self.qimage.height())
def createBottomGroupBox(self):
self.bottomGroupBox = QGroupBox()
self.sliderBrightness = QSlider(Qt.Horizontal, self)
brightnessLabel = QLabel("Brightness:")
brightnessLabel.setBuddy(self.sliderBrightness)
self.sliderBrightness.setTickPosition(QSlider.TicksBelow)
self.sliderBrightness.setTickInterval(1)
self.sliderBrightness.setValue(100)
self.sliderBrightness.setMinimum(0)
self.sliderBrightness.setMaximum(200)
self.brightnessValueLabel = QLabel("1")
self.sliderContrast = QSlider(Qt.Horizontal, self)
contrastLabel = QLabel("Contrast:")
contrastLabel.setBuddy(contrastLabel)
self.sliderContrast.setValue(1)
self.sliderContrast.setMinimum(0)
self.sliderContrast.setMaximum(2)
self.contrastValueLabel = QLabel("1")
sliderSharpness = QSlider(Qt.Horizontal, self)
sharpnessLabel = QLabel("Sharpness:")
sharpnessLabel.setBuddy(sharpnessLabel)
sliderSharpness.setValue(1)
sliderSharpness.setMinimum(0)
sliderSharpness.setMaximum(2)
self.sharpnessValueLabel = QLabel("1")
savePushButton = QPushButton("Save")
savePushButton.clicked.connect(self.saveImage("image.png", "PNG"))
self.sliderBrightness.valueChanged.connect(self.valueChangeBrightness)
self.sliderContrast.valueChanged.connect(self.valueChangeContrast)
sliderSharpness.valueChanged.connect(self.valueChangeSharpness)
layout = QVBoxLayout()
layout.addWidget(brightnessLabel)
layout.addWidget(self.sliderBrightness, 0)
layout.addWidget(self.brightnessValueLabel)
layout.addWidget(contrastLabel)
layout.addWidget(self.sliderContrast, 1)
layout.addWidget(sharpnessLabel)
layout.addWidget(sliderSharpness, 2)
layout.addWidget(savePushButton, 3)
self.bottomGroupBox.setLayout(layout)
def saveImage(self, fileName, fileFormat):
self.editImage.save(fileName, fileFormat)
def valueChangeBrightness(self, sliderValue):
factor = float(sliderValue)/100
enhancer_object = ImageEnhance.Brightness(self.image)
self.editImage = enhancer_object.enhance(factor)
self.brightnessValueLabel.setText(str(self.sliderBrightness.value()))
def valueChangeContrast(self, factor):
enhancer_object = ImageEnhance.Contrast(self.image)
enhancer_object.enhance(factor)
def valueChangeSharpness(self, factor):
enhancer_object = ImageEnhance.Sharpness(self.image)
enhancer_object.enhance(factor)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
The main problem in the OP code is that it has not updated the image shown. For example, if the docs is reviewed, it is understood that the enhance method returns the modified image but is neither saved nor displayed.
On the other hand the application of the changes must be in cascade (one behind the other).
There are also errors such as not verifying that the filename is an empty string, in addition that the clicked signal is connected to a shutdown, not to which an evaluated function returns.
Considering the above, the solution is:
from PIL.ImageQt import Image, ImageQt
from PIL import ImageEnhance
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import (
QApplication,
QDialog,
QGridLayout,
QLabel,
QPushButton,
QGroupBox,
QSlider,
QVBoxLayout,
QFileDialog,
)
class MainWindow(QDialog):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.createTopGroupBox()
self.createBottomGroupBox()
mainLayout = QGridLayout(self)
mainLayout.addWidget(self.topGroupBox, 0, 0)
mainLayout.addWidget(self.bottomGroupBox, 1, 0)
self.setWindowTitle("Photo Editor")
self.resize(800, 800)
self.input_image = None
self.output_image = None
def createTopGroupBox(self):
self.topGroupBox = QGroupBox()
openImgButton = QPushButton("Open Image")
openImgButton.clicked.connect(self.getImage)
self.label = QLabel("Your Photo")
layout = QVBoxLayout()
layout.addWidget(openImgButton)
layout.addWidget(self.label)
layout.addStretch(1)
self.topGroupBox.setLayout(layout)
def getImage(self):
fname, _ = QFileDialog.getOpenFileName(
self, "Open file", "", "Image files (*.jpeg *.jpg *.gif *.bmp *.png)"
)
if fname:
self.input_image = Image.open(fname)
self.show_image(self.input_image)
def show_image(self, image):
qimage = ImageQt(image)
self.label.setPixmap(QPixmap.fromImage(qimage))
def createBottomGroupBox(self):
self.bottomGroupBox = QGroupBox()
self.sliderBrightness = QSlider(
Qt.Horizontal,
tickPosition=QSlider.TicksBelow,
tickInterval=1,
value=100,
minimum=0,
maximum=200,
)
brightnessLabel = QLabel("Brightness:")
brightnessLabel.setBuddy(self.sliderBrightness)
self.brightnessValueLabel = QLabel()
self.brightnessValueLabel.setNum(self.sliderBrightness.value())
self.sliderContrast = QSlider(Qt.Horizontal, value=1, minimum=0, maximum=2)
contrastLabel = QLabel("Contrast:")
contrastLabel.setBuddy(self.sliderContrast)
self.contrastValueLabel = QLabel()
self.contrastValueLabel.setNum(self.sliderContrast.value())
self.sliderSharpness = QSlider(Qt.Horizontal, value=1, minimum=0, maximum=2)
sharpnessLabel = QLabel("Sharpness:")
sharpnessLabel.setBuddy(self.sliderSharpness)
self.sharpnessValueLabel = QLabel()
self.sharpnessValueLabel.setNum(self.sliderSharpness.value())
savePushButton = QPushButton("Save")
savePushButton.clicked.connect(lambda: self.saveImage("image.png", "PNG"))
self.sliderBrightness.valueChanged.connect(self.update_image)
self.sliderContrast.valueChanged.connect(self.update_image)
self.sliderSharpness.valueChanged.connect(self.update_image)
layout = QVBoxLayout()
layout.addWidget(brightnessLabel)
layout.addWidget(self.sliderBrightness)
layout.addWidget(self.brightnessValueLabel)
layout.addWidget(contrastLabel)
layout.addWidget(self.sliderContrast)
layout.addWidget(self.contrastValueLabel)
layout.addWidget(sharpnessLabel)
layout.addWidget(self.sliderSharpness)
layout.addWidget(self.sharpnessValueLabel)
layout.addWidget(savePushButton)
self.bottomGroupBox.setLayout(layout)
def saveImage(self, fileName, fileFormat):
if self.output_image is not None:
self.output_image.save(fileName, fileFormat)
def update_image(self):
if self.input_image is not None:
factor_brightness = self.sliderBrightness.value() / 100.0
factor_contrast = self.sliderContrast.value()
factor_sharpness = self.sliderSharpness.value()
enhancer_object = ImageEnhance.Brightness(self.input_image)
image = enhancer_object.enhance(factor_brightness)
enhancer_object = ImageEnhance.Contrast(image)
image = enhancer_object.enhance(factor_contrast)
enhancer_object = ImageEnhance.Sharpness(image)
self.output_image = enhancer_object.enhance(factor_sharpness)
self.show_image(self.output_image)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Related
I am writing a little program, but the buttons don't work
as I expected.
I wish the text to change state when I click on the button of that text.
Here is the code to test it:
from sys import exit
from sys import argv
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QVBoxLayout, QLabel, QWidget, QLineEdit
class MainWindow(QWidget):
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.screenWidth = 1920
self.screenHeight = 1080
self.windowWidth = 1000
self.windowHeight = 800
self.setWindowTitle("test 19")
self.setGeometry((self.screenWidth - self.windowWidth) // 2, (self.screenHeight - self.windowHeight) // 2, self.windowWidth, self.windowHeight)
self.initUi()
def initUi(self) -> None:
mainLayout = QVBoxLayout()
headLayout = QHBoxLayout()
nameLabel = QLabel("Name")
headLayout.addWidget(nameLabel)
mainLayout.addItem(headLayout)
row1 = Row("google.com")
mainLayout.addItem(row1.returnValues())
row2 = Row("yahoo.com")
mainLayout.addItem(row2.returnValues())
for i in range(20):
rowi = Row(f"{i}")
mainLayout.addItem(rowi.returnValues())
self.setLayout(mainLayout)
class Row():
def __init__(self, name) -> None:
super().__init__()
self.rowLayout = QHBoxLayout()
self.nameLineEdit = QLineEdit(f"{name}")
self.nameLineEdit.setDisabled(True)
self.rowLayout.addWidget(self.nameLineEdit)
self.hiddenOrShowButton = QPushButton("")
self.hiddenOrShowButton.clicked.connect(self.hiddenOrShow)
self.rowLayout.addWidget(self.hiddenOrShowButton)
def returnValues(self) -> QHBoxLayout:
return self.rowLayout
def hiddenOrShow(self) -> None:
if self.nameLineEdit.echoMode() == QLineEdit.EchoMode.Password:
self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Normal)
else:
self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Password)
if __name__ == "__main__":
app = QApplication(argv)
window = MainWindow()
window.show()
exit(app.exec())
I expect the text to change state when I click on the button of that text.
Your best bet is to subclass QHBoxLayout, as suggested by musicamante in the comments, and your Row class isn't that far off from doing just that.
The only changes that really need to be made are to add in the subclass reference in your Row to Row(QHBoxLayout), then would want to remove the self.rowLayout line because the Row class would become the layout. and you would change all the references to it to just self instead of self.rowLayout.
For example:
from sys import exit
from sys import argv
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QVBoxLayout, QLabel, QWidget, QLineEdit
class MainWindow(QWidget):
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.screenWidth = 1920
self.screenHeight = 1080
self.windowWidth = 1000
self.windowHeight = 800
self.setWindowTitle("test 19")
self.setGeometry((self.screenWidth - self.windowWidth) // 2, (self.screenHeight - self.windowHeight) // 2, self.windowWidth, self.windowHeight)
self.initUi()
def initUi(self) -> None:
mainLayout = QVBoxLayout()
headLayout = QHBoxLayout()
nameLabel = QLabel("Name")
headLayout.addWidget(nameLabel)
mainLayout.addLayout(headLayout)
row1 = Row("google.com") # the row now is the layout
mainLayout.addLayout(row1) # so you add it directly to the main layout
row2 = Row("yahoo.com")
mainLayout.addLayout(row2) # use addLayout instead of addItem
for i in range(20):
rowi = Row(f"{i}")
mainLayout.addLayout(rowi)
self.setLayout(mainLayout)
class Row(QHBoxLayout): # use subclass declaration
def __init__(self, name):
super().__init__()
self.nameLineEdit = QLineEdit(f"{name}")
self.nameLineEdit.setDisabled(True)
self.addWidget(self.nameLineEdit) # add the widget to self
self.hiddenOrShowButton = QPushButton("")
self.hiddenOrShowButton.clicked.connect(self.hiddenOrShow)
self.addWidget(self.hiddenOrShowButton) # same thing here
# the returnValues method can be removed.
def hiddenOrShow(self) -> None:
if self.nameLineEdit.echoMode() == QLineEdit.EchoMode.Password:
self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Normal)
else:
self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Password)
if __name__ == "__main__":
app = QApplication(argv)
window = MainWindow()
window.show()
exit(app.exec())
I have a custom Media Player, that can display images and videos with the help of PyQt. Media player is implemented by the following code in python:
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout, QVBoxLayout,
QLabel, \
QSlider, QStyle, QSizePolicy, QFileDialog
import sys
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtGui import QIcon, QPalette
from PyQt5.QtCore import Qt, QUrl
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt5 Media Player")
self.setGeometry(350, 100, 700, 500)
self.setWindowIcon(QIcon('player.png'))
p =self.palette()
p.setColor(QPalette.Window, Qt.black)
self.setPalette(p)
self.init_ui()
self.show()
def init_ui(self):
#create media player object
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
#create videowidget object
videowidget = QVideoWidget()
#create open button
openBtn = QPushButton('Open Video')
openBtn.clicked.connect(self.open_file)
#create button for playing
self.playBtn = QPushButton()
self.playBtn.setEnabled(False)
self.playBtn.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
self.playBtn.clicked.connect(self.play_video)
#create slider
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0,0)
self.slider.sliderMoved.connect(self.set_position)
#create label
self.label = QLabel()
self.label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
#create hbox layout
hboxLayout = QHBoxLayout()
hboxLayout.setContentsMargins(0,0,0,0)
#set widgets to the hbox layout
hboxLayout.addWidget(openBtn)
hboxLayout.addWidget(self.playBtn)
hboxLayout.addWidget(self.slider)
#create vbox layout
vboxLayout = QVBoxLayout()
vboxLayout.addWidget(videowidget)
vboxLayout.addLayout(hboxLayout)
vboxLayout.addWidget(self.label)
self.setLayout(vboxLayout)
self.mediaPlayer.setVideoOutput(videowidget)
#media player signals
self.mediaPlayer.stateChanged.connect(self.mediastate_changed)
self.mediaPlayer.positionChanged.connect(self.position_changed)
self.mediaPlayer.durationChanged.connect(self.duration_changed)
def open_file(self):
filename, _ = QFileDialog.getOpenFileName(self, "Open Video")
if filename != '':
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(filename)))
self.playBtn.setEnabled(True)
def play_video(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
self.mediaPlayer.pause()
else:
self.mediaPlayer.play()
def mediastate_changed(self, state):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
self.playBtn.setIcon(
self.style().standardIcon(QStyle.SP_MediaPause)
)
else:
self.playBtn.setIcon(
self.style().standardIcon(QStyle.SP_MediaPlay)
)
def position_changed(self, position):
self.slider.setValue(position)
def duration_changed(self, duration):
self.slider.setRange(0, duration)
def set_position(self, position):
self.mediaPlayer.setPosition(position)
def handle_errors(self):
self.playBtn.setEnabled(False)
self.label.setText("Error: " + self.mediaPlayer.errorString())
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
What I am trying to do is get the x and y coordinates of the edges of the video/image played each time and while it feels like it should be easy I really can't figure out how to do this. As displayed in the images every video/image may have different corner positions. The only thing I could think of was getting videowidgets dimensions but it wasn't right.
print(videowidget.height())
print(videowidget.width())
print(videowidget.x())
print(videowidget.y())
I'm not sure if this exactly answers your question but I found a sort of solution by comparing aspect ratios of the video and the widget:
class VideoClickWidget(QVideoWidget):
def __init__(self):
QVideoWidget.__init__(self)
def mouseReleaseEvent(self, event):
widget_width = self.frameGeometry().width()
widget_height = self.frameGeometry().height()
widget_ratio = widget_width / widget_height
video_width = self.mediaObject().metaData("Resolution").width()
video_height = self.mediaObject().metaData("Resolution").height()
video_ratio = video_width / video_height
x, y = event.pos().x(), event.pos().y()
# It's wider
if widget_ratio > video_ratio:
percentage = video_ratio / widget_ratio
# we know that video occupies $percentage$ of the widget
dead_zone = int(np.round(widget_width * ((1 - percentage) / 2)))
new_x = np.clip(x - dead_zone, 0, widget_width - 2 * dead_zone)
print(new_x, y)
else:
percentage = widget_ratio / video_ratio
dead_zone = int(np.round(widget_height * ((1 - percentage) / 2)))
new_y = np.clip(y - dead_zone, 0, widget_height - 2 * dead_zone)
print(x, new_y)
super(QVideoWidget, self).mouseReleaseEvent(event)
I have the following test script.
from PyQt5.QtWidgets import *
import sys
class MW(QMainWindow):
def __init__(self):
super(MW, self).__init__()
widget = QWidget()
widget.setStyleSheet('QWidget {background-color:#000000; color:#FFFFFF}'
"QPushButton:hover {background-color:#202020}")
self.setCentralWidget(widget)
box = QVBoxLayout(widget)
but1_box = QHBoxLayout()
but1 = QPushButton("Button 1")
lab1 = QLabel("Label 1")
but1_box.addWidget(but1)
but1_box.addWidget(lab1)
box.addLayout(but1_box)
but2_box = QHBoxLayout()
but2 = QPushButton("Button 2")
lab2 = QLabel("Label 2")
but2_box.addWidget(but2)
but2_box.addWidget(lab2)
box.addLayout(but2_box)
self.show()
app = QApplication(sys.argv)
mw = MW()
sys.exit(app.exec_())
If I hover over the PushButton it changes its color to a gray and I want that the associated Label changes its color while hovering over the button.
It is not possible to implement directly using the pseudo-states of the Qt Style Sheet but you will have to use an eventFilter that detects the changes of the hover (enter and leave) and that modifies the stylesheet of the other elements
from PyQt5.QtCore import pyqtSignal, QEvent, QObject
from PyQt5.QtWidgets import (
QApplication,
QHBoxLayout,
QLabel,
QMainWindow,
QPushButton,
QVBoxLayout,
QWidget,
)
import sys
class HoverListener(QObject):
entered = pyqtSignal()
leaved = pyqtSignal()
def __init__(self, widget):
super(HoverListener, self).__init__(widget)
self._widget = widget
self.widget.installEventFilter(self)
#property
def widget(self):
return self._widget
def eventFilter(self, obj, event):
if obj == self.widget:
if event.type() == QEvent.Enter:
self.entered.emit()
elif event.type() == QEvent.Leave:
self.leaved.emit()
return super(HoverListener, self).eventFilter(obj, event)
class MW(QMainWindow):
def __init__(self):
super(MW, self).__init__()
widget = QWidget()
widget.setStyleSheet(
"QWidget {background-color:#000000; color:#FFFFFF}"
"QPushButton:hover {background-color:#202020}"
)
self.setCentralWidget(widget)
but1 = QPushButton("Button 1")
lab1 = QLabel("Label 1")
hover_listener1 = HoverListener(but1)
hover_listener1.entered.connect(
lambda label=lab1: label.setStyleSheet("background-color:#202020")
)
hover_listener1.leaved.connect(lambda label=lab1: label.setStyleSheet(""))
but2 = QPushButton("Button 2")
lab2 = QLabel("Label 2")
hover_listener2 = HoverListener(but2)
hover_listener2.entered.connect(
lambda label=lab2: label.setStyleSheet("background-color:#202020")
)
hover_listener2.leaved.connect(lambda label=lab2: label.setStyleSheet(""))
box = QVBoxLayout(widget)
but1_box = QHBoxLayout()
but1_box.addWidget(but1)
but1_box.addWidget(lab1)
box.addLayout(but1_box)
but2_box = QHBoxLayout()
but2_box.addWidget(but2)
but2_box.addWidget(lab2)
box.addLayout(but2_box)
self.show()
app = QApplication(sys.argv)
mw = MW()
sys.exit(app.exec_())
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QFileDialog, QPushButton, QLineEdit,QVBoxLayout, QHBoxLayout
from PyQt5.QtCore import *
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QDialog, QVBoxLayout
import Updated_encrypt
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.title = 'Encrypt/Decrypt'
self.top = 200
self.left = 500
self.width = 400
self.height = 300
self.InitWindow()
def InitWindow(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
vbox = QVBoxLayout()
self.button1 = QPushButton('Encrypt')
self.button1.clicked.connect(self.openSecondDialog)
self.button2 = QPushButton('Decrypt')
vbox.addWidget(self.button1)
vbox.addWidget(self.button2)
self.setLayout(vbox)
self.show()
def openSecondDialog(self):
hbox = QVBoxLayout()
mydialog = QDialog(self)
mydialog.show()
self.button2 = QPushButton('Check Image')
self.button2.clicked.connect(self.getImage)
hbox.addWidget(self.button2)
self.setLayout(hbox)
self.show()
def getImage(self):
hbox = QHBoxLayout()
file_Name = QFileDialog.getOpenFileName(self,
'OpenFile',
'',
'')
image_path = file_Name[0]
updatedImage = Updated_encrypt.decrypt(image_path, 123)
pixmap = QPixmap(updatedImage)
self.label.setPixmap(QPixmap(pixmap))
self.resize(pixmap.width(), pixmap.height())
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
I have my code set up to implement an algorithm to modify an image when my I select it from my pop up dialogue. What I am trying to accomplish is for the image to pop up in a separate window when I click the encrypt button. I can't seem to get anything to pop up in the separate window aside from the window itself. Any help would be appreciated.
You have at least the following errors:
The "hbox" created is being added to the window and not to the QDialog: self.setLayout(hbox), it must be mydialog.setLayout(hbox).
Do not use the same name for 2 different objects as they can cause problems, in your case there are 2 QPushButton assigned to the variable "self.button2".
You try to use the variable "self.label" but never believe it.
Considering the above we can make the following improvements:
Use more descriptive names to easily distinguish their function.
If you are going to have a window that has a different objective, it is better to create a class.
The above avoid the indicated problems, considering the above the solution is:
import sys
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import (
QApplication,
QDialog,
QFileDialog,
QHBoxLayout,
QLabel,
QPushButton,
QVBoxLayout,
QWidget,
)
import Updated_encrypt
class Dialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.load_image_btn = QPushButton("Check Image")
self.load_image_btn.clicked.connect(self.load_image)
self.image_lbl = QLabel()
lay = QVBoxLayout(self)
lay.addWidget(self.load_image_btn)
lay.addWidget(self.image_lbl)
def load_image(self):
image_path, _ = QFileDialog.getOpenFileName(self, "OpenFile", "", "")
if image_path:
updatedImage = Updated_encrypt.decrypt(image_path, 123)
pixmap = QPixmap(updatedImage)
self.image_lbl.setPixmap(QPixmap(pixmap))
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.title = "Encrypt/Decrypt"
self.InitWindow()
def InitWindow(self):
self.setWindowTitle(self.title)
self.setGeometry(200, 500, 400, 300)
self.encrypt_btn = QPushButton("Encrypt")
self.encrypt_btn.clicked.connect(self.openSecondDialog)
self.decrypt_btn = QPushButton("Decrypt")
vbox = QVBoxLayout(self)
vbox.addWidget(self.encrypt_btn)
vbox.addWidget(self.decrypt_btn)
def openSecondDialog(self):
dialog = Dialog(self)
dialog.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
so I am trying to use PyQt5 to put a scroll area inside of a tab. Just playing around with a system that reads the serial port.
The issue I am having is that although I set a QVBoxLayout, the size does not seem to adjust to what I want it to be. It seems to be taking its minimum size and not adjusting.
I tried looking at the documentation on QSizePolicy on the website provided, but unfortunately it is all labeled as TODO.
https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtwidgets/qsizepolicy.html
I was wondering if anyone had some experience with this?
import sys
from PyQt5.QtWidgets import QMainWindow, QSizePolicy, QLabel, QGridLayout, QToolTip, QPlainTextEdit, QScrollArea, QApplication, QPushButton, QWidget, QAction, QTabWidget, QHBoxLayout, QVBoxLayout
from PyQt5.QtGui import *
from PyQt5.QtCore import pyqtSlot, QDateTime, Qt, pyqtSignal, QObject, QSize
import datetime
import serial
import serial.tools.list_ports
import threading
class FDSerial(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.connected = False
self.fd_line = ""
newAct = QAction(QIcon('icn/001-file.png'), 'New', self)
newAct.triggered.connect(self.init_sc)
self.toolbar = self.addToolBar('New')
self.toolbar.addAction(newAct)
openAct = QAction(QIcon('icn/002-folder.png'), 'Open', self)
self.toolbar.addAction(openAct)
connectAct = QAction(QIcon('icn/003-pendrive.png'), 'Connect', self)
connectAct.triggered.connect(self.find_port)
self.toolbar.addAction(connectAct)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
editMenu = menubar.addMenu('&Settings')
toolsMenu = menubar.addMenu('&Tools')
sessionMenu = menubar.addMenu('&Session')
helpMenu = menubar.addMenu('&Help')
self.statusBar().showMessage('Ready')
self.table_widget = LayoutWidgets(self)
self.setCentralWidget(self.table_widget)
self.setGeometry(400, 400, 800, 600)
self.setWindowTitle('FD Serial Demo')
self.show()
self.c = Communicate()
self.c.serialStuff.connect(lambda: self.table_widget.add_row(self.fd_line))
def init_sc(self):
self.ser = serial.Serial()
self.ser.baudrate = 115200
self.is_connected = False
self.tests_run = 0
self.port_found = False
def find_port(self):
if self.is_connected is False:
self.is_connected = True
else:
self.is_connected = False
for port in serial.tools.list_ports.comports():
if port.vid == 5824 and port.pid == 1155:
self.ser.port = str(port.device)
self.port_found = True
print("Found")
if self.port_found is False:
print("Not found")
x = threading.Thread(target=self.talk_module)
x.start()
def talk_module(self):
self.ser.open()
while self.is_connected is True:
self.fd_line = self.ser.readline().decode()
print(self.fd_line)
self.c.serialStuff.emit()
self.ser.close()
class Communicate(QObject):
serialStuff = pyqtSignal()
class LayoutWidgets(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
self.thisthat = 0
self.mySizePolicy = QSizePolicy()
self.mySizePolicy.setHorizontalStretch(1)
self.mySizePolicy.setVerticalStretch(1)
# self.mySizePolicy.setHeightForWidth(False)
# self.mySizePolicy.setHorizontalPolicy(QSizePolicy.Maximum)
# self.mySizePolicy.setVerticalPolicy(QSizePolicy.Maximum)
self.tabs = QTabWidget()
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tabs.addTab(self.tab1, "Serial CANFD Interface")
self.tabs.addTab(self.tab2, "Data Visualizer")
self.tab1.layout = QVBoxLayout()
self.tab2.layout = QVBoxLayout()
self.scrollArea = QScrollArea(self.tab1)
self.scrollArea.setWidgetResizable(True)
# self.widget = QWidget()
# self.scrollArea.setWidget(self.widget)
self.layout_SArea = QVBoxLayout(self.scrollArea)
self.layout_SArea.setSpacing(0)
self.tab1.layout.addWidget(self.scrollArea)
self.scrollArea.setSizePolicy(self.mySizePolicy)
self.scrollArea.setStyleSheet("background-color:'#d3f3c8'")
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
self.qtextbig = QPlainTextEdit()
self.qtextbig.setSizePolicy(self.mySizePolicy)
self.qtextbig.setReadOnly(False)
self.layout_SArea.addWidget(self.qtextbig)
def add_row(self, row):
self.this = str(row)
self.this2 = str(datetime.datetime.now().time())
self.thisthat = self.thisthat + 1
self.qtextbig.appendPlainText(self.this)
self.qtextbig.appendPlainText(self.this2)
self.qtextbig.appendPlainText(str(self.thisthat))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = FDSerial()
sys.exit(app.exec_())
Here is how the GUI looks right now. The scroll are is way too small! It is in green.
I am looking for the scroll area to take the whole tab size, and then adjust as I adjust the window size. Would appreciate any pointers.
Thanks!
The problem has nothing to do with the QSizePolicy, they are not really necessary. The problem is that you are not using layouts. I think that using the following instruction:
self.tab1.layout = QVBoxLayout()
self.tab2.layout = QVBoxLayout()
add a layout to each tab, but it is only pointing out that there is a new property called layout that takes the value of the QVBoxLayout and that deletes the reference to the layout method of the tab, ie it only deletes the access to the tab1.layout() method, and doing it is a bad practice.
Considering the above I have used the following code:
# ...
class LayoutWidgets(QWidget):
def __init__(self, parent=None):
super(QWidget, self).__init__(parent)
layout = QVBoxLayout(self)
self.thisthat = 0
self.tabs = QTabWidget()
layout.addWidget(self.tabs)
self.tab1 = QWidget()
self.tab2 = QWidget()
self.tabs.addTab(self.tab1, "Serial CANFD Interface")
self.tabs.addTab(self.tab2, "Data Visualizer")
lay = QVBoxLayout(self.tab1)
self.scrollArea = QScrollArea(widgetResizable=True)
self.scrollArea.setStyleSheet("background-color:'#d3f3c8'")
lay.addWidget(self.scrollArea)
layout_SArea = QVBoxLayout(self.scrollArea)
self.qtextbig = QPlainTextEdit(readOnly=False)
layout_SArea.addWidget(self.qtextbig)
def add_row(self, row):
self.this = str(row)
self.this2 = str(datetime.datetime.now().time())
self.thisthat = self.thisthat + 1
self.qtextbig.appendPlainText(self.this)
self.qtextbig.appendPlainText(self.this2)
self.qtextbig.appendPlainText(str(self.thisthat))
# ...