When building a GUI application using python and the qt framework. I would like to reuse certain UI elements without defining them over and over again. In my example I would like to create a drop down menu defining the number of rows with y(number) and result(number)
Application example
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton,
QLineEdit, QGridLayout, QLabel)
from math import sqrt
class program(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Program')
flow = QLabel('x1')
pressuredrop_1 = QLabel('y1')
pressuredrop_2 = QLabel('y2 ')
kv = QLabel('result 1')
kv_2 = QLabel('result 2')
grid = QGridLayout()
grid.setSpacing(10)
self.setLayout(grid)
self.setGeometry(300,300,300,150)
self.btn = QPushButton('Calculate', self)
self.flow = QLineEdit(self)
self.pd = QLineEdit(self)
self.result = QLineEdit(self)
self.pd_2 = QLineEdit(self)
self.kvresult_2 = QLineEdit(self)
grid.addWidget(flow, 1,0)
grid.addWidget(self.flow, 1, 1)
grid.addWidget(pressuredrop_1, 2,0)
grid.addWidget(self.pd, 2, 1)
grid.addWidget(pressuredrop_2, 3,0)
grid.addWidget(self.pd_2, 3, 1)
grid.addWidget(kv, 2,2)
grid.addWidget(self.result, 2,3)
grid.addWidget(kv_2, 3,2)
grid.addWidget(self.kvresult_2, 3,3)
grid.addWidget(self.btn, 4,1)
self.btn.clicked.connect(self.calculate)
self.btn.clicked.connect(self.calculate_2)
self.show()
Related
I created a QStacedLayout and nested 2 widgets in it.
However, as I understand it, if one widget is larger than the other, then QStackedLayout seems to be trying to equalize the size of the larger one to the smaller one.
Because of this, part of the content of the 2nd widget is "eaten" and appears only after I move the window.
How can this be fixed?
Large Widget Code:
from PySide6.QtWidgets import QFrame, QWidget, QLabel
from PySide6.QtWidgets import QVBoxLayout, QPushButton
from PySide6.QtCore import Qt
import tech
class AboutMe(QFrame):
def __init__(self):
super(AboutMe, self).__init__()
with open(tech.resource_path("ui\\assets\\styles\\AboutMe.qss"), "r", encoding="utf-8") as f:
self.style = f.read()
self.setStyleSheet(self.style)
self.layout = QVBoxLayout()
self.layout.setAlignment(Qt.AlignTop)
self.layout.setContentsMargins(5, 5, 5, 5)
self.layout.setSpacing(3)
self.text = QLabel("text "*800)
self.text.setWordWrap(True)
self.layout.addWidget(self.text)
self.setLayout(self.layout)
class AboutPage(QWidget):
def __init__(self):
super(AboutPage, self).__init__()
self.layout = QVBoxLayout()
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.setSpacing(3)
self.aboutme = AboutMe()
self.layout.addWidget(self.aboutme)
self.setLayout(self.layout)
Main Widget Code:
class MainWidget(QWidget):
def __init__(self, bot, parent):
super(MainWidget, self).__init__()
self.page_layout = QStackedLayout()
self.page_layout.setSpacing(0)
self.page_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout = QVBoxLayout()
self.main_layout.setSpacing(3)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_page = MainPage(bot)
self.about_page = AboutPage()
self.page_layout.addWidget(self.main_page)
self.page_layout.addWidget(self.about_page)
self.page_layout.setCurrentIndex(0)
self.bar = CustomBar(parent)
self.main_layout.addWidget(self.bar)
self.main_layout.addLayout(self.page_layout)
self.setLayout(self.main_layout)
Result:
First Widget:
Second (larger):
When I switched to at least a pixel:
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_())
I try to make the QTextEdit change its width value to the length of the text that is entered in it.
But the problem is that when using the resize property it does not do anything and does not change the size
I am obeying the length of the current word in the list and that value is the one I try to send as a property width() to the QTextEdit
to get something like this:
from PyQt5.QtWidgets import QMainWindow,QWidget,QVBoxLayout,QApplication,QTextEdit,QPushButton,QScrollArea
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.lista = ["one","two","abcdefghijklmn","zxyw","xyxyxyxyx"]
self.widget = QWidget(self)
self.layout = QVBoxLayout(self.widget)
self.area = QScrollArea(self)
self.area.resize(400,300)
self.area.setWidget(self.widget)
self.area.setWidgetResizable(True)
self.plain =QTextEdit(self)
self.plain.move(0,305)
self.plain.resize(400,50)
self.boton = QPushButton(self)
self.boton.move(0,360)
self.boton.setText("Press")
self.boton.clicked.connect(self.Test)
def Test(self):
for i in self.lista:
longitud = len(i)*6.3
print(longitud)
self.text = QTextEdit(self)
self.text.document().setPlainText(i)
self.text.setReadOnly(True)
self.text.resize(longitud,10)
self.layout.addWidget(self.text)
app = QApplication([])
m = Main()
m.show()
m.resize(600,400)
app.exec()
Actually what I need is that the QTextEdit that are created to fill the QScrollArea conform to the size of the length of text characters
This is the result I get but what I need is that the QTextEdit have the width() to where the line ends
Here is my attempt to solve this problem using font metrics to measure the size of the text box contents:
import sys
from PyQt5.QtGui import QFontMetrics
from PyQt5.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QApplication, QTextEdit, QPushButton, QScrollArea
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.lista = ["one", "two", "abcdefghijklmn", "zxyw", "xyxyxyxyx"]
self.widget = QWidget(self)
self.layout = QVBoxLayout(self.widget)
self.area = QScrollArea(self)
self.area.resize(400,300)
self.area.setWidget(self.widget)
self.area.setWidgetResizable(True)
self.plain = QTextEdit(self)
self.plain.move(0,305)
self.plain.resize(400,50)
self.boton = QPushButton(self)
self.boton.move(0,360)
self.boton.setText("Press")
self.boton.clicked.connect(self.Test)
def Test(self):
for i in self.lista:
text = QTextEdit(self)
text.document().setPlainText(i)
font = text.document().defaultFont()
fontMetrics = QFontMetrics(font)
textSize = fontMetrics.size(0, text.toPlainText())
w = textSize.width() + 10
h = textSize.height() + 10
text.setMinimumSize(w, h)
text.setMaximumSize(w, h)
text.resize(w, h)
text.setReadOnly(True)
self.layout.addWidget(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
m = Main()
m.show()
m.resize(600, 400)
sys.exit(app.exec_())
Result:
I'm making a first come first served scheduler using pyqt5.
I have the main window which includes textbox asking the user for scheduler type, when button "GO" is clicked, the second window is opened which asks the user for more information about the scheduler like process numbers and burst time .
When button "GO" on the second window is clicked, a Gantt chart should appear after processing the information.
The problem is that the button on the second window is not working at all.
I have found a similar question, but I didn't quite got the solution, plus I'm not using JSON.
Code:
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import QMainWindow,QApplication, QComboBox, QDialog,QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,QVBoxLayoutQSpinBox, QTextEdit, QVBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
import matplotlib.pyplot as plt
import numpy as np
import linked_list
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50,50,500,300)
self.home()
self.show()
def home(self):
self.label2=QLabel(self)
self.label2.setText("Type of Scheduler")
self.label2.move(10,50)
self.textbox2=QLineEdit(self)
self.textbox2.move(100,50)
self.button=QPushButton("Go",self)
self.button.move(0,200)
self.button.clicked.connect(self.runcode)
def runcode(self):
schedular_type=self.textbox2.text()
if(schedular_type=="FCFS"):
self.close()
self.fcfs=Window2(self)
Self.fcfs.__init__()
class Window2(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50,50,500,300)
self.home()
self.show()
def home(self):
self.label1=QLabel(self)
self.label1.setText("No of Processes")
self.label1.move(10,0) #col ,row
self.textbox=QLineEdit(self)
self.textbox.move(100,0)
self.label3=QLabel(self)
self.label3.setText("Processess Names")
self.label3.move(10,100)
self.label4=QLabel(self)
self.label4.setText("Burst Time")
self.label4.move(120,100)
self.label5=QLabel(self)
self.label5.setText("Arrival Time")
self.label5.move(200,100)
self.names=QLineEdit(self)
self.names.move(10,150)
# self.names.resize(100,160)
self.burst=QLineEdit(self)
self.burst.move(120,150)
#self.burst.resize(100,160)
self.arrival=QLineEdit(self)
self.arrival.move(250 ,150)
#self.arrival.resize(100,160)
#self.textEdit=QTextEdit(self)
#self.textEdit.move(20,250)
self.button=QPushButton("Go",self)
self.button.move(0,200)
self.button.clicked.connect(self.fcfs)
def fcfs(self):
//
def main():
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Set a parent to second window, also you are calling ____init____ method of Window2 twice.
Here is the fixed code :
import sys
from PyQt5 import QtGui
from PyQt5.QtWidgets import (QMainWindow, QApplication, QComboBox,
QDialog, QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox,
QHBoxLayout, QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox,
QTextEdit, QVBoxLayout)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
import matplotlib.pyplot as plt
import numpy as np
import linked_list
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50, 50, 500, 300)
self.home()
self.show()
def home(self):
self.label2 = QLabel(self)
self.label2.setText("Type of Scheduler")
self.label2.move(10, 50)
self.textbox2 = QLineEdit(self)
self.textbox2.move(100, 50)
self.button = QPushButton("Go", self)
self.button.move(0, 200)
self.button.clicked.connect(self.runcode)
def runcode(self):
schedular_type = self.textbox2.text()
if(schedular_type == "FCFS"):
self.close()
fcfs = Window2(self)
# Do not call __init__ explicitly below
# fcfs.__init__()
class Window2(QMainWindow):
def __init__(self,parent=None):
super().__init__(parent)
# always try to set a parent
self.setWindowTitle("My Program")
self.setWindowIcon(QtGui.QIcon("download.jpg"))
self.setGeometry(50, 50, 500, 300)
self.home()
self.show()
def home(self):
self.label1 = QLabel(self)
self.label1.setText("No of Processes")
self.label1.move(10, 0) # col ,row
self.textbox = QLineEdit(self)
self.textbox.move(100, 0)
self.label3 = QLabel(self)
self.label3.setText("Processess Names")
self.label3.move(10, 100)
self.label4 = QLabel(self)
self.label4.setText("Burst Time")
self.label4.move(120, 100)
self.label5 = QLabel(self)
self.label5.setText("Arrival Time")
self.label5.move(200, 100)
self.names = QLineEdit(self)
self.names.move(10, 150)
# self.names.resize(100,160)
self.burst = QLineEdit(self)
self.burst.move(120, 150)
# self.burst.resize(100,160)
self.arrival = QLineEdit(self)
self.arrival.move(250, 150)
# self.arrival.resize(100,160)
# self.textEdit=QTextEdit(self)
# self.textEdit.move(20,250)
self.button = QPushButton("Go", self)
self.button.move(0, 200)
self.button.clicked.connect(self.fcfs)
def fcfs(self):
no_of_process = self.textbox.text()
process_names = self.names.text()
burst_time = self.burst.text()
arrival_time = self.arrival.text()
names_list = process_names.split()
burst_list = burst_time.split()
arrival_list = arrival_time.split()
# integer conversion
burst_list = [int(i) for i in burst_list]
arrival_list = [int(i) for i in arrival_list]
no_of_process = int(no_of_process)
ls = LinkedList()
i = 0
while i < no_of_process:
ls.append(names_list[i], burst_list[i], arrival_list[i])
i = i + 1
time = arrival_list[0]
j = 0
start = []
end = []
name = []
while j < (ls.size()):
while(time < arrival_list[j]):
time = time + 1
start.append(time)
time = time + burst_list[j]
end.append(time)
name.append(names_list[j])
j = j + 1
waiting_time = 0
k = 0
average_waiting = 0
while k < (ls.size()):
waiting_time = waiting_time + \
end[k] - arrival_list[k] - burst_list[k]
average_waiting = waiting_time / ls.size()
k = k + 1
x = name
begin = np.array(start)
end = np.array(end)
plt.barh(range(len(begin)), end - begin, left=begin)
plt.yticks(range(len(begin)), x)
#plt.text(0.6,1.5,('average waiting is ',average_waiting))
plt.annotate(("average waiting is", average_waiting), xy=(0.5, 1.49))
plt.show()
def main():
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
the crucial part is:
def __init__(self,parent=None):
super().__init__(parent)
I have following code for my PyQt5 GUI:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QCalendarWidget, QMainWindow, QGridLayout, QLayout, QTableWidget, QHeaderView, QLabel, QHBoxLayout, QVBoxLayout, QLineEdit, QComboBox
from PyQt5.QtCore import QDate, Qt
from datetime import date, datetime
class CalendarWindow(QMainWindow):
def __init__(self, parent=None):
super(CalendarWindow, self).__init__(parent)
self.setUpUI()
def setUpUI(self):
self.setGeometry(50, 50, 1200, 700)
# Labels
self.label_events = QLabel(self)
self.label_new_event = QLabel(self)
self.label_event_name = QLabel(self)
self.label_start_date = QLabel(self)
self.label_repeat = QLabel(self)
self.label_description = QLabel(self)
# Labels parameters
self.label_events.setAlignment(Qt.AlignCenter)
self.label_events.setText("Wydarzenia danego dnia:")
# self.label_new_event.setAlignment(Qt.AlignCenter)
self.label_new_event.setText("Dodaj event:")
self.label_event_name.setText("Nazwa eventu:")
self.label_start_date.setText("Data eventu:")
self.label_repeat.setText("Powtarzalność eventu:")
self.label_description.setText("Opis:")
# TextEdits
self.text_event_name = QLineEdit(self)
self.text_start_date = QLineEdit(self)
self.text_description = QLineEdit(self)
# TextEdits parameters
# ComboBoxes
self.combo_repeat = QComboBox(self)
# ComboBoxes parameters
self.combo_repeat.addItems(
["No", "Day", "Week", "Two weeks", "Month", "Half a year", "Year"])
# Widgets
self.setWindowTitle("Python Calendar App")
self.calendar_widget = QCalendarWidget(self)
# User date select event
self.calendar_widget.clicked[QDate].connect(self.dateChanged)
self.events_list_widget = QTableWidget(self)
self.events_list_widget.setColumnCount(5)
self.events_list_widget.setHorizontalHeaderLabels(
["ID", "Name", "Date", "Repetition", "Description"])
# Columns stretched and fit
self.events_list_widget.horizontalHeader().setSectionResizeMode(
QHeaderView.Stretch)
self.main_widget = QWidget(self)
self.main_layout = QGridLayout(self.main_widget)
self.main_layout.sizeConstraint = QLayout.SetDefaultConstraint
self.main_layout.addWidget(self.calendar_widget, 0, 0)
self.init_sublayouts()
self.main_layout.addLayout(self.sublayout_events, 0, 1)
self.main_layout.addLayout(self.sublayout_new_event, 0, 2)
self.main_layout.setColumnStretch(0, 1)
self.main_layout.setColumnStretch(1, 3)
self.main_layout.setColumnStretch(2, 2)
self.main_widget.setLayout(self.main_layout)
self.setCentralWidget(self.main_widget)
def init_sublayouts(self):
# Events sublayout
self.sublayout_events = QVBoxLayout()
self.sublayout_events.addWidget(self.label_events)
self.sublayout_events.addWidget(self.events_list_widget)
# New event sublayout
self.sublayout_new_event = QVBoxLayout()
self.sublayout_new_event.addWidget(self.label_new_event)
self.sublayout_new_event_grid = QGridLayout()
self.sublayout_new_event_grid.addWidget(self.label_event_name, 1, 0)
self.sublayout_new_event_grid.addWidget(self.text_event_name, 1, 1)
self.sublayout_new_event_grid.addWidget(self.label_start_date, 2, 0)
self.sublayout_new_event_grid.addWidget(self.text_start_date, 2, 1)
self.sublayout_new_event_grid.addWidget(self.label_repeat, 3, 0)
self.sublayout_new_event_grid.addWidget(self.combo_repeat, 3, 1)
self.sublayout_new_event_grid.addWidget(self.label_description, 4, 0)
self.sublayout_new_event_grid.addWidget(self.text_description, 4, 1)
self.sublayout_new_event.addLayout(self.sublayout_new_event_grid)
def dateChanged(self, qdate):
print("Date changed to:", self.getDaysEvents())
selected_date = self.getDaysEvents()
# self.events_list_widget.addItem(selected_date.strftime("%d/%m/%y"))
def getDaysEvents(self):
selected_date = self.calendar_widget.selectedDate()
return selected_date.toPyDate()
if __name__ == '__main__':
app = QApplication(sys.argv)
foo = CalendarWindow()
foo.show()
sys.exit(app.exec_())
When you lanuch it, it looks like this:
I have a problem with that 3rd column. I want the Dodaj event: label to be at the top, and those textboxes with their labels to be not far away under it. The relevant code is in init_sublayouts under # New event sublayout comment. I tried to make those textboxes into QGridLayout and Dodaj event and this QGridLayout to QVBoxLabout, but u see what happened. I also tried to make every row of my QGridLayout a separate QHBoxLayout, and the result was pretty the same. Is there a way to do it? I did something similar in the column 2, where I have a QLabel stacked on top of QTableWidget, but in the column 3 it seems to be not working as expected.
void QBoxLayout::addStretch(int stretch = 0)
Adds a stretchable space (a QSpacerItem) with zero minimum size and stretch factor stretch to the end of this box layout.
Try it:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QCalendarWidget, QMainWindow, QGridLayout, QLayout, QTableWidget, QHeaderView, QLabel, QHBoxLayout, QVBoxLayout, QLineEdit, QComboBox
from PyQt5.QtCore import QDate, Qt
from datetime import date, datetime
class CalendarWindow(QMainWindow):
def __init__(self, parent=None):
super(CalendarWindow, self).__init__(parent)
self.setUpUI()
def setUpUI(self):
self.setGeometry(50, 50, 1200, 700)
# Labels
self.label_events = QLabel(self)
self.label_new_event = QLabel(self)
self.label_event_name = QLabel(self)
self.label_start_date = QLabel(self)
self.label_repeat = QLabel(self)
self.label_description = QLabel(self)
# Labels parameters
self.label_events.setAlignment(Qt.AlignCenter)
self.label_events.setText("Wydarzenia danego dnia:")
self.label_new_event.setAlignment(Qt.AlignCenter) # +
self.label_new_event.setText("Dodaj event:")
self.label_event_name.setText("Nazwa eventu:")
self.label_start_date.setText("Data eventu:")
self.label_repeat.setText("Powtarzalność eventu:")
self.label_description.setText("Opis:")
# TextEdits
self.text_event_name = QLineEdit(self)
self.text_start_date = QLineEdit(self)
self.text_description = QLineEdit(self)
# TextEdits parameters
# ComboBoxes
self.combo_repeat = QComboBox(self)
# ComboBoxes parameters
self.combo_repeat.addItems(
["No", "Day", "Week", "Two weeks", "Month", "Half a year", "Year"])
# Widgets
self.setWindowTitle("Python Calendar App")
self.calendar_widget = QCalendarWidget(self)
# User date select event
self.calendar_widget.clicked[QDate].connect(self.dateChanged)
self.events_list_widget = QTableWidget(self)
self.events_list_widget.setColumnCount(5)
self.events_list_widget.setHorizontalHeaderLabels(
["ID", "Name", "Date", "Repetition", "Description"])
# Columns stretched and fit
self.events_list_widget.horizontalHeader().setSectionResizeMode(
QHeaderView.Stretch)
self.main_widget = QWidget(self)
self.main_layout = QGridLayout(self.main_widget)
self.main_layout.sizeConstraint = QLayout.SetDefaultConstraint
self.main_layout.addWidget(self.calendar_widget, 0, 0)
self.init_sublayouts()
self.main_layout.addLayout(self.sublayout_events, 0, 1)
self.main_layout.addLayout(self.sublayout_new_event, 0, 2)
self.main_layout.setColumnStretch(0, 1)
self.main_layout.setColumnStretch(1, 3)
self.main_layout.setColumnStretch(2, 2)
self.main_widget.setLayout(self.main_layout)
self.setCentralWidget(self.main_widget)
def init_sublayouts(self):
# Events sublayout
self.sublayout_events = QVBoxLayout()
self.sublayout_events.addWidget(self.label_events)
self.sublayout_events.addWidget(self.events_list_widget)
# New event sublayout
self.sublayout_new_event = QVBoxLayout()
self.sublayout_new_event.addWidget(self.label_new_event)
self.sublayout_new_event.addStretch(1) # +
self.sublayout_new_event_grid = QGridLayout()
self.sublayout_new_event_grid.addWidget(self.label_event_name, 1, 0)
self.sublayout_new_event_grid.addWidget(self.text_event_name, 1, 1)
self.sublayout_new_event_grid.addWidget(self.label_start_date, 2, 0)
self.sublayout_new_event_grid.addWidget(self.text_start_date, 2, 1)
self.sublayout_new_event_grid.addWidget(self.label_repeat, 3, 0)
self.sublayout_new_event_grid.addWidget(self.combo_repeat, 3, 1)
self.sublayout_new_event_grid.addWidget(self.label_description, 4, 0)
self.sublayout_new_event_grid.addWidget(self.text_description, 4, 1)
self.sublayout_new_event.addLayout(self.sublayout_new_event_grid)
self.sublayout_new_event.addStretch(20) # +
def dateChanged(self, qdate):
print("Date changed to:", self.getDaysEvents())
selected_date = self.getDaysEvents()
# self.events_list_widget.addItem(selected_date.strftime("%d/%m/%y"))
def getDaysEvents(self):
selected_date = self.calendar_widget.selectedDate()
return selected_date.toPyDate()
if __name__ == '__main__':
app = QApplication(sys.argv)
foo = CalendarWindow()
foo.show()
sys.exit(app.exec_())