The task is to write a robot emulator. I have three classes in my code: ControlWidget, BoardWidget and Emulator (the main widget that should combine Control and Board in one window). I'm going to draw some pictures on the BoardWidget with the use of QPainter.
class ControlWidget(QFrame):
def __init__(self):
super().__init__()
self._vbox_main = QVBoxLayout()
self.initUI()
def initUI(self):
# ... adding some buttons
self.setLayout(self._vbox_main)
self.setGeometry(50, 50, 600, 600)
self.setWindowTitle('Robot Controller')
class BoardWidget(QWidget):
def __init__(self):
super().__init__()
self._robot_pixmap = QPixmap("robo.png")
self.initUI()
def initUI(self):
self.setStyleSheet("QWidget { background: #123456 }")
self.setFixedSize(300, 300)
self.setWindowTitle("Robot Emulator")
Both of them appear nicely if shown in different windows:
class Emulator(QWidget):
def __init__(self):
super().__init__()
self._control = ControlWidget()
self._board = BoardWidget()
self._board.show()
self._control.show()
But the magic comes here. I want my Emulator show both the board and control:
class Emulator(QWidget):
def __init__(self):
super().__init__()
self._control = ControlWidget()
self._board = BoardWidget()
self.initUI()
self.show()
def initUI(self):
layout = QBoxLayout(QBoxLayout.RightToLeft, self)
layout.addWidget(self._control)
layout.addStretch(1)
layout.addWidget(self._board)
self.setLayout(layout)
self.setWindowTitle('Robot Emulator')
self.setWindowIcon(QIcon("./assets/robo.png"))
# self._board.update()
I've killed three hours trying to fix it. I've tried to present my board as a QPixmap over the QLabel inside the QBoxLayout. I tried to replace QBoxLayout with the QHBoxLayout. Nothing makes any difference.
As #ekhumoro stated in the comments, it is necessary to add the QPixmap to a QLabel and then set it on the BoardWidget layout manager with setLayout() function.
One solution could be the next reimplementation of BoardWidget class:
class BoardWidget(QWidget):
def __init__(self):
super().__init__()
self._robot_pixmap = QPixmap("robo.png")
self.label = QLabel()
self.label.setPixmap(self._robot_pixmap)
self._vbox_board = QVBoxLayout()
self.initUI()
def initUI(self):
self._vbox_board.addWidget(self.label)
self.setLayout(self._vbox_board)
self.setStyleSheet("QWidget { background: #123456 }")
self.setFixedSize(300, 300)
self.setWindowTitle("Robot Emulator")
The result is shown here:
Related
When setting a label in the init of a QWidget the text is shown properly, however on changing the text with the press of a button the text is not shown fully.
It is limited at the char length of the old string. How can this be solved?
Thanks in advance!
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setGeometry(500, 500, 500, 420)
Button("Change it!", self).set_tool_tip("Change the label text").resize().move(0, 40).on_click(
self.change_label)
self.Label = QLabel(self)
self.Label.setText("I'm going to change and get bigger!")
self.Label.move(0, 65)
def change_label(self):
self.Label.setText("I'm bigger then I was before, unfortunately I'm not fully shown. Can you help me? :)")
You have to change size manually using self.Label.resize(width, height) in change_label. But you don't know what value use as width
Better use any layout manager and it will resize widget automatically.
Example with layout manager Vertical Boxes - QVBoxLayout
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
self.setLayout(layout)
self.button = QPushButton("Change it!", self)
self.button.clicked.connect(self.change_label)
layout.addWidget(self.button)
self.label = QLabel(self)
self.label.setText("I'm going to change and get bigger!")
layout.addWidget(self.label)
def change_label(self):
self.label.setText("I'm bigger then I was before, unfortunately I'm not fully shown. Can you help me? :)")
app = QApplication([])
main = MainWindow()
main.show()
app.exec()
I have
class View(QtWidgets.QLabel):
def __init__(self):
super(View,self).__init__()
self.cropLabel = QtWidgets.QLabel(self)
self.label = QtWidgets.QLabel(self)
self.ogpixmap = QtGui.QPixmap()
fileName = r'C:/Users/user11.HPO-SAMAT/Pictures/Lake.jpg'
image = QtGui.QImage(fileName)
self.pixmap = QtGui.QPixmap.fromImage(image)
self.label.setPixmap(self.pixmap)
self.label.adjustSize()
and then I call this class:
class Viewer(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.view = View()
self.scroller = QtWidgets.QScrollArea()
self.scroller.setWidget(self.view)
self.scroller.setWidgetResizable(True)
self.scroller.adjustSize()
But QScrollArea does not seem to work (noscrollbar though the image is visible and I can expand QMainWindows to see it entirely)
What am I doing wrong ?
I do not understand so they put several labels inside View, if we remove the labels that are other we get what you want.
class View(QtWidgets.QLabel):
def __init__(self, parent=None):
super(View,self).__init__(parent)
fileName = "/home/qhipa/Pictures/1475777628875.jpg"
self.pixmap = QtGui.QPixmap(fileName)
self.setPixmap(self.pixmap)
class Viewer(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.view = View(self)
self.scroller = QtWidgets.QScrollArea(self)
self.setCentralWidget(self.scroller)
self.scroller.setWidget(self.view)
self.scroller.setWidgetResizable(True)
self.scroller.adjustSize()
Instead if you want to get several labels, it is better that the View class inherits from QWidget.
class View(QtWidgets.QWidget):
def __init__(self, parent=None):
super(View,self).__init__(parent)
self.setLayout(QtWidgets.QVBoxLayout())
self.cropLabel = QtWidgets.QLabel(self)
self.label = QtWidgets.QLabel(self)
self.layout().addWidget(self.cropLabel)
self.layout().addWidget(self.label)
self.pixmap = QtGui.QPixmap("/home/qhipa/Pictures/1475777628875.jpg")
self.label.setPixmap(self.pixmap)
self.label.adjustSize()
I am getting wrong layout in PyQT5. What am I doing wrong? Is there some predefined small field size or similar? I created main window as QMainWindow and inside it a widget as central widget. This is how it looks like:
class Main(QWidget):
"""The main widget with label and LineEdit"""
def __init__(self, parent=None):
super().__init__(parent)
self.initUi()
def initUi(self):
"""Initialize the UI of the main widget"""
self.mySourceLabel = QLabel("Select your file:")
self.mySourceLine = QLineEdit()
self.mySourceLine.setPlaceholderText("File name here")
# Set layout
grid = QGridLayout()
#grid.setSpacing(5)
grid.addWidget(self.mySourceLabel, 0, 0)
grid.addWidget(self.mySourceLine, 1, 0)
self.setLayout(grid)
class MyApp(QMainWindow):
"""Main application class"""
def __init__(self, parent=None):
super().__init__(parent)
self.initUi()
def initUi(self):
"""Initialize UI of an application"""
# main window size, title
self.setGeometry(400, 300, 400, 300)
self.setWindowTitle("Version upgrade ")
# create instance of a class Main
self.main = Main(self)
# create central widget, create grid layout
centralWidget = QWidget()
centralLayout = QGridLayout()
centralWidget.setLayout(centralLayout)
When you pass the parent to a QWidget this will locate a position with respect to its parent and generate widgets like the ones you have obtained, to solve this, layouts are used, QMainWindow is a special QWidget since it has predefined elements, so it already has a layout:
In QMainWindow the widget must be added to the centralwidget with the setCentralWidget function, in your case:
class MyApp(QMainWindow):
"""Main application class"""
def __init__(self, parent=None):
super().__init__(parent)
self.initUi()
def initUi(self):
[...]
centralWidget = Main(self)
self.setCentralWidget(centralWidget)
complete code:
class Main(QWidget):
"""The main widget with label and LineEdit"""
def __init__(self, parent=None):
super().__init__(parent)
self.initUi()
def initUi(self):
"""Initialize the UI of the main widget"""
self.mySourceLabel = QLabel("Select your file:")
self.mySourceLine = QLineEdit()
self.mySourceLine.setPlaceholderText("File name here")
# Set layout
grid = QGridLayout()
#grid.setSpacing(5)
grid.addWidget(self.mySourceLabel, 0, 0)
grid.addWidget(self.mySourceLine, 1, 0)
self.setLayout(grid)
class MyApp(QMainWindow):
"""Main application class"""
def __init__(self, parent=None):
super().__init__(parent)
self.initUi()
def initUi(self):
"""Initialize UI of an application"""
# main window size, title
self.setGeometry(400, 300, 400, 300)
self.setWindowTitle("Version upgrade ")
# create central widget, create grid layout
centralWidget = Main(self)
self.setCentralWidget(centralWidget)
Screenshot:
I have a QMainWindow with a QStackedWidget as the central widget, and having been switching between layouts by changing the current widget of this central widget.
This has been working fine, but now I am trying to make one of these possible layouts scrollable and this is the result:
Code for MainWindow class:
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.central_widget = QtGui.QStackedWidget()
self.setCentralWidget(self.central_widget)
#-- On load open main menu
self.showMenu()
# Go to the menu screen
def showMenu(self):
widget_menu = WidgetMain(self)
widget_menu.btnConfigu.clicked.connect(self.showConfig)
self.central_widget.addWidget(widget_menu)
self.central_widget.setCurrentWidget(widget_menu)
self.resize(420,350)
# Go to the config screen
def showConfigu(self):
widget_configu = WidgetOptions(self)
self.central_widget.addWidget(widget_configu)
self.central_widget.setCurrentWidget(widget_configu)
Code for WidgetOptions class:
class WidgetOptions(QtGui.QWidget):
def __init__(self, parent=None):
super(WidgetOptions, self).__init__(parent)
#Container Widget
widget = QtGui.QWidget()
layoutRightContainer = QtGui.QVBoxLayout()
for _ in range(11):
btn = QtGui.QPushButton("test")
layoutRightContainer.addWidget(btn)
widget.setLayout(layoutRightContainer)
widget
self.setFixedHeight(300)
#Scroll Area Properties
scroll = QtGui.QScrollArea()
scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
scroll.setWidgetResizable(True)
scroll.setWidget(widget)
layoutMain = QtGui.QHBoxLayout()
layoutMain.addWidget(widget)
I've tried numerous tweaks to the set sizes, and making different containers non-/resizable. What works outside of a StackedWidget doesn't seem to work within one. There also doesn't seem to be any questions on SO with such a situation.
self.setLayout(layoutMain)
I solved this by making the WidgetOptions class itself an extension of QScrollArea rather than a QWidget containing the QScrollArea
Code for WidgetOptions class:
class WidgetOptions(QtGui.QScrollArea):
def __init__(self, parent=None):
super(WidgetOptions, self).__init__(parent)
layoutLeft = QtGui.QVBoxLayout()
self.btnVariables = QtGui.QPushButton("Variables")
self.btnGroups = QtGui.QPushButton("Groups")
layoutLeft.addWidget(self.btnVariables)
layoutLeft.addWidget(self.btnGroups)
#Container Widget
widget = QtGui.QWidget()
layoutRightContainer = QtGui.QVBoxLayout()
for _ in range(11):
btn = QtGui.QPushButton("test")
layoutRightContainer.addWidget(btn)
widget.setLayout(layoutRightContainer)
#Scroll Area Properties
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setWidgetResizable(True)
self.setWidget(widget)
self.setWidget(widget)
I am trying to run class AddTQuestions from a def in class AddTest but it wont work!! It opens the window AddTQuestions for a split-second then closes it straight away?!
The code is shown here:
import sys
from PyQt4 import QtCore, QtGui
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
RunClassAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self)
RunClassAction.triggered.connect(self.run)
self.toolbar = self.addToolBar('Exit')
self.toolbar.addAction(RunClassAction)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Why Wont this Woooorkkkkk')
self.show()
def run(self):
AddQuestion = AddTQuestions()
AddQuestion.show()
class AddTQuestions(QtGui.QMainWindow):
def __init__(self, parent=None):
super(AddTQuestions, self).__init__(parent)
self.welldone = QtGui.QLabel('WellDone')
self.button = QtGui.QPushButton('Press Me')
layout = QtGui.QVBoxLayout()
layout.addWidget(self.welldone)
layout.addWidget(self.button)
self.setLayout(layout)
print("hello")
if __name__ == '__main__':
app = QtGui.QApplication([])
window = Example()
window.show()
app.exec_()
The object get's garbage collected, since you don't hold any reference to it when the function ends.
add them as class variables like this and the window stays open.
self.AddQuestion = AddTQuestions()
self.AddQuestion.show()