Проблемы с PyQt5
Решил написать небольшой тестовый проект, чтобы освоится с PyQt5. Все работает, но почему-то после возврата с третьей страницы (где ввод данных) разметка ломается и все улетает вверх.
main.py:
from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget, QFileDialog, QGridLayout, QCheckBox, QTableWidget,QTableWidgetItem,QLineEdit, QScrollArea,QHeaderView
from PyQt5.QtGui import QPixmap, QCursor, QRegExpValidator
from PyQt5.QtCore import QRegExp
from PyQt5 import QtWidgets
import numpy as np
from collections import Counter
from PyQt5 import QtGui, QtCore
from PyQt5.QtGui import QCursor
import sys
from os.path import exists
import pandas as pd
# File names, window properties, products data
FILE_NAME_PRODUCTS = 'history.csv'
FILE_NAME_EXPENSES = 'expenses.csv'
WINDOW_WIDTH = 1440
WINDOW_HEIGHT = 650
PRODUCTS = {}
for i in range(1, 22):
PRODUCTS[str(i)] = 0
class Base(QWidget):
def __init__(self):
super().__init__()
# Base wndow parameters
self.setWindowTitle('Business Turtle')
self.setStyleSheet("background: #1E152A;")
self.setFixedWidth(WINDOW_WIDTH)
self.setFixedHeight(WINDOW_HEIGHT)
self.setLayout(QGridLayout())
# list where will be all widgets from current page
self.widgets = []
# Starting programm with Start window
current_window = Start_Window(self)
current_window.Add_Widgets()
current_window.Show_Widgets()
def Clear_widgets(self):
for _widget in self.widgets:
_widget.hide()
self.widgets = []
def Next_Window(self, window):
self.Clear_widgets()
window.Add_Widgets()
window.Show_Widgets()
class Start_Window(QWidget):
def __init__(self,base):
super().__init__()
# base - to save widgets to the 'base list'
self.base = base
def Add_Widgets(self):
# Main page logo
# Main page heading
heading = QLabel('BUSINESS TURTLE')
heading.setStyleSheet('font-size:38px;'
'color:"#8FE381";')
heading.setAlignment(QtCore.Qt.AlignCenter)
self.base.widgets.append(heading)
self.base.layout().addWidget(self.base.widgets[-1], 1, 0,1,3)
# button for price calculations
button_calc = QPushButton('РАСЧЕТ', clicked=lambda: self.base.Next_Window(Products_Window(self.base)))
button_calc.setFixedWidth(400)
button_calc.setStyleSheet('*{font-size:30px;'
'color:"#837569";'
'letter-spacing:4px;'
'border: 4px solid "#FFA9E7";'
'border-radius: 20px;'
'margin-bottom:30px;}'
'*:hover{'
'background: #FFA9E7;'
'color:#1E152A;}')
self.base.widgets.append(button_calc)
self.base.layout().addWidget(self.base.widgets[-1],2,1)
def Show_Widgets(self):
self.base.show()
class Products_Window(QWidget):
def __init__(self,base):
super().__init__()
self.base = base
def Add_Widgets(self):
# small logo
# Creating checkBox for every element in PRODUCT database
row, column = 1,0
for _product in PRODUCTS:
el = QCheckBox(_product, self)
el.setStyleSheet('border: 1px solid #837569;'
'border-radius : 5px;'
'letter-spacing:2px;'
'font-size:15px;'
'font-weight:600;'
'color: #837569;'
'margin-left:50%;'
'letter-spacing:2;'
'margin-right:50%;'
'padding-top:5px;'
'padding-bottom:5px;'
'margin-bottom:20px;')
PRODUCTS[_product] = el
if row % 8 ==0 :
row = 1
column +=1
self.base.widgets.append(el)
self.base.layout().addWidget(self.base.widgets[-1], row,column)
row += 1
# button for next price calculations
button_next = QPushButton('ДАЛЕЕ', clicked= lambda: self.Update_Products())
button_next.setFixedWidth(325)
button_next.setStyleSheet('*{'
'font-size:20px;'
'background: #FFA9E7;'
'color:"#1E152A";'
'letter-spacing:4px;'
'border: 4px solid #FFA9E7;'
'border-radius: 15px;'
'margin-bottom:20px;}'
'*:hover{'
'background: transparent;'
'color: #837569;}')
self.base.widgets.append(button_next)
self.base.layout().addWidget(self.base.widgets[-1],11,2)
#button for analysis
button_previous = QPushButton('НАЗАД', clicked= lambda: self.base.Next_Window(Start_Window(self.base)))
button_previous.setFixedWidth(325)
button_previous.setStyleSheet('*{'
'font-size:20px;'
'color:"#837569";'
'letter-spacing:4px;'
'border: 4px solid #FFA9E7;'
'border-radius: 15px;'
'margin-bottom:20px;}'
'*:hover{'
'background: #FFA9E7;'
'color:#1E152A;}')
self.base.widgets.append(button_previous)
self.base.layout().addWidget(self.base.widgets[-1],11,0)
def Show_Widgets(self):
self.base.show()
def Update_Products(self):
for _product in PRODUCTS:
if PRODUCTS[_product].isChecked():
PRODUCTS[_product] = 1
else:
PRODUCTS[_product] = 0
self.base.Next_Window(Input_Prices_Window(self.base))
class Input_Prices_Window(QWidget):
def __init__(self,base):
super().__init__()
#new dict with users prices and amount
self.PRODUCTS_WITH_PRICES = {}
self.base = base
def Add_Widgets(self):
row, column = 2,0
names = [i for i in PRODUCTS if PRODUCTS[i] == 1]
self.expenses = ['Имя заказа','Дата', 'Курс евро [Покупка] [₽]', 'Курс евро [Доставка] [₽]',
'Курс евро [Налоги] [₽]', 'Доставка До [€]', 'Доставка После [€]',
'Таможня [₽]']
layout = QtWidgets.QVBoxLayout(self)
scrollArea = QScrollArea(self)
scrollAreaWidgetContents = QtWidgets.QWidget()
scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
scrollArea.setWidgetResizable(True)
ScrollGridLayout = QGridLayout(scrollAreaWidgetContents)
scrollArea.setWidget(scrollAreaWidgetContents)
scrollArea.setStyleSheet('border: 1px solid #837569;'
'border-radius:20px;')
self.base.widgets.append(scrollArea)
self.base.layout().addWidget(scrollArea, 1, 0, 10, 3)
# regex for validating users input
reg_ex_number = QRegExp("([0-9]*[.])?[0-9]+")
#dont validate date corectness ONLY FORMAT
reg_ex_date = QRegExp("^[0-3]?[0-9]/[0-3]?[0-9]/(?:[0-9]{2})?[0-9]{2}$")
for _product in names + self.expenses:
if _product not in names:
if _product == 'Дата':
el = QLabel(_product)
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
self.base.widgets.append(el)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column)
input_box_price = QLineEdit(self)
input_box_price.setPlaceholderText(' Дата [dd/mm/yyyy]')
input_box_price.setStyleSheet('*{border: 1px solid #837569;'
'border-radius : 5px;'
'letter-spacing:2px;'
'font-size:15px;'
'font-weight:600;'
'color: #837569;}'
'*:focus{'
'outline: none !important;'
'border: 3px solid #837569;'
'border-radius: 5px;}')
input_validator = QRegExpValidator(reg_ex_date, input_box_price)
input_box_price.setValidator(input_validator)
self.base.widgets.append(input_box_price)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column+1, 1, 1)
elif _product == 'Имя заказа':
el = QLabel(_product)
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
self.base.widgets.append(el)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column)
input_box_price = QLineEdit(self)
input_box_price.setPlaceholderText(' Придумайте имя')
input_box_price.setStyleSheet('*{'
'border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;}'
'*:focus{'
'outline: none !important;'
'border: 3px solid #837569;'
'border-radius: 5px;}')
self.base.widgets.append(input_box_price)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column+1, 1, 1)
else:
el = QLabel(_product )
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing:2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
self.base.widgets.append(el)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column)
input_box_price = QLineEdit(self)
input_box_price.setPlaceholderText(' Цена')
input_box_price.setStyleSheet('*{'
'border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;}'
'*:focus{'
'outline: none !important;'
'border: 3px solid #837569;'
'border-radius: 5px;}')
input_validator = QRegExpValidator(reg_ex_number, input_box_price)
input_box_price.setValidator(input_validator)
self.base.widgets.append(input_box_price)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column+1, 1, 1)
self.PRODUCTS_WITH_PRICES[_product] = [input_box_price]
else:
el = QLabel(_product + ' [€]')
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
input_box_price = QLineEdit(self)
input_box_amount = QLineEdit(self)
input_box_price.setStyleSheet('*{'
'border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;}'
'*:focus{'
'outline: none !important;'
'border: 3px solid #837569;'
'border-radius: 5px;}')
input_box_price.setPlaceholderText(' Цена')
input_validator = QRegExpValidator(reg_ex_number, input_box_price)
input_box_price.setValidator(input_validator)
input_box_amount.setStyleSheet('*{'
'border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;}'
'*:focus{'
'outline: none !important;'
'border: 3px solid #837569;'
'border-radius: 5px;}')
input_box_amount.setPlaceholderText(' Количество')
input_validator = QRegExpValidator(reg_ex_number, input_box_amount)
input_box_amount.setValidator(input_validator)
self.base.widgets.append(el)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column)
self.base.widgets.append(input_box_price)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column+1)
self.base.widgets.append(input_box_amount)
ScrollGridLayout.addWidget(self.base.widgets[-1], row,column+2)
self.PRODUCTS_WITH_PRICES[_product] = [input_box_price,input_box_amount]
row += 1
# button for price calculations
button_next = QPushButton('ДАЛЕЕ', clicked= lambda: self.Update_Products())
button_next.setFixedWidth(400)
button_next.setStyleSheet('*{'
'font-size:20px;'
'background: #FFA9E7;'
'color:"1E152A";'
'letter-spacing:4px;'
'border: 4px solid "#FFA9E7";'
'border-radius: 15px;'
'margin-bottom:20px;}'
'*:hover{'
'background: transparent;'
'color: #837569;}')
#button for analysis
button_previous = QPushButton('НАЗАД', clicked= lambda: self.base.Next_Window(Products_Window(self.base)))
button_previous.setFixedWidth(400)
button_previous.setStyleSheet('*{'
'font-size:20px;'
'color:"#837569";'
'letter-spacing:4px;'
'border: 4px solid "#FFA9E7";'
'border-radius: 15px;'
'margin-bottom:20px;}'
'*:hover{'
'background: #FFA9E7;'
' color:#1E152A;}')
self.base.widgets.append(button_next)
self.base.layout().addWidget(self.base.widgets[-1],11, 2)
self.base.widgets.append(button_previous)
self.base.layout().addWidget(self.base.widgets[-1],11,0)
def Show_Widgets(self):
self.base.show()
def Update_Products(self):
print('ok')
app = QApplication([])
window = Base()
window.show()
sys.exit(app.exec_())
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Обычно такая задача делается с использованием виджета QStackedWidget.
Класс QStackedWidget предоставляет стек виджетов, в котором одновременно виден только один виджет.
Стили лучше писать в одном месте не загромождая код логики.
import sys
from os.path import exists
import pandas as pd
import numpy as np
from collections import Counter
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qt import *
# File names, window properties, products data
FILE_NAME_PRODUCTS = 'history.csv'
FILE_NAME_EXPENSES = 'expenses.csv'
WINDOW_WIDTH = 1440
WINDOW_HEIGHT = 650
PRODUCTS = {}
for i in range(1, 22):
PRODUCTS[str(i)] = 0
class Products_Window(QWidget):
def __init__(self):
super().__init__()
self.layout = QGridLayout(self)
row, column = 1, 0
for _product in PRODUCTS:
el = QCheckBox(_product, self)
PRODUCTS[_product] = el
if row % 8 ==0 :
row = 1
column +=1
self.layout.addWidget(el, row, column)
row += 1
# --------------------------------------------> vvvvvvvvvvvvvvvvvvvvvvvv ...
self.button_next = QPushButton('ДАЛЕЕ', objectName='button_next')
self.layout.addWidget(self.button_next, 11, 2)
self.button_previous = QPushButton('НАЗАД', objectName='button_previous')
self.layout.addWidget(self.button_previous, 11, 0)
class Input_Prices_Window(QWidget):
def __init__(self):
super().__init__()
self.PRODUCTS_WITH_PRICES = {}
# !!! +++
self.layout = QGridLayout(self) # !!! +++
row, column = 2, 0
names = [i for i in PRODUCTS if PRODUCTS[i] == 1]
self.expenses = [
'Имя заказа','Дата', 'Курс евро [Покупка] [₽]', 'Курс евро [Доставка] [₽]',
'Курс евро [Налоги] [₽]', 'Доставка До [€]', 'Доставка После [€]',
'Таможня [₽]'
]
# - layout = QtWidgets.QVBoxLayout(self)
scrollArea = QScrollArea(self)
scrollArea.setObjectName('scrollArea') # +++ setObjectName
scrollAreaWidgetContents = QtWidgets.QWidget()
scrollAreaWidgetContents.setObjectName('scrollAreaWidgetContents') # +++ setObjectName #
# ??? scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
scrollArea.setWidgetResizable(True)
ScrollGridLayout = QGridLayout(scrollAreaWidgetContents)
scrollArea.setWidget(scrollAreaWidgetContents)
self.layout.addWidget(scrollArea, 1, 0, 10, 3)
# regex for validating users input
reg_ex_number = QRegExp("([0-9]*[.])?[0-9]+")
#dont validate date corectness ONLY FORMAT
reg_ex_date = QRegExp("^[0-3]?[0-9]/[0-3]?[0-9]/(?:[0-9]{2})?[0-9]{2}$")
for _product in names + self.expenses:
if _product not in names:
if _product == 'Дата':
el = QLabel(_product)
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
ScrollGridLayout.addWidget(el, row, column)
input_box_price = QLineEdit(self)
input_box_price.setPlaceholderText(' Дата [dd/mm/yyyy]')
input_validator = QRegExpValidator(reg_ex_date, input_box_price)
input_box_price.setValidator(input_validator)
ScrollGridLayout.addWidget(input_box_price, row, column+1, 1, 1)
elif _product == 'Имя заказа':
el = QLabel(_product)
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
ScrollGridLayout.addWidget(el, row, column)
input_box_price = QLineEdit(self, placeholderText=' Придумайте имя')
# input_box_price.setPlaceholderText(' Придумайте имя')
ScrollGridLayout.addWidget(input_box_price, row, column+1, 1, 1)
else:
el = QLabel(_product )
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing:2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
ScrollGridLayout.addWidget(el, row, column)
input_box_price = QLineEdit(self)
input_box_price.setPlaceholderText(' Цена')
input_validator = QRegExpValidator(reg_ex_number, input_box_price)
input_box_price.setValidator(input_validator)
ScrollGridLayout.addWidget(input_box_price, row, column+1, 1, 1)
self.PRODUCTS_WITH_PRICES[_product] = [input_box_price]
else:
el = QLabel(_product + ' [€]')
el.setStyleSheet('border: 1px solid #837569;'
'border-radius: 5px;'
'letter-spacing: 2px;'
'font-size: 15px;'
'font-weight: 600;'
'color: #837569;')
input_box_price = QLineEdit(self)
input_box_amount = QLineEdit(self)
input_box_price.setPlaceholderText(' Цена')
input_validator = QRegExpValidator(reg_ex_number, input_box_price)
input_box_price.setValidator(input_validator)
input_box_amount.setPlaceholderText(' Количество')
input_validator = QRegExpValidator(reg_ex_number, input_box_amount)
input_box_amount.setValidator(input_validator)
ScrollGridLayout.addWidget(el, row, column)
ScrollGridLayout.addWidget(input_box_price, row, column+1)
ScrollGridLayout.addWidget(input_box_amount, row, column+2)
self.PRODUCTS_WITH_PRICES[_product] = [input_box_price,input_box_amount]
row += 1
# button for price calculations
button_next = QPushButton('ДАЛЕЕ',
clicked=self.update_products, objectName='button_next')
#button for analysis
self.button_previous = QPushButton('НАЗАД', objectName='button_previous')
self.layout.addWidget(button_next, 11, 2)
self.layout.addWidget(self.button_previous, 11, 0)
def update_products(self):
print('ok')
class Start_Window(QWidget):
def __init__(self):
super().__init__()
self.heading = QLabel('BUSINESS TURTLE', objectName='heading')
self.heading.setAlignment(QtCore.Qt.AlignCenter)
self.button_calc = QPushButton('РАСЧЕТ', objectName='button_calc')
# ??? self.button_calc.setFixedWidth(400)
self.layout = QGridLayout(self)
self.layout.addWidget(self.heading, 1, 0, 1, 3)
self.layout.addWidget(self.button_calc, 2, 1)
class Base(QWidget):
def __init__(self):
super().__init__()
# Base wndow parameters
self.setWindowTitle('Business Turtle')
self.setObjectName('centralwidget')
self.current_window = Start_Window()
self.current_window.button_calc.clicked.connect(
lambda: self.stackedWidget.setCurrentIndex(1))
self.products_window = Products_Window()
self.products_window.button_next.clicked.connect(
lambda: self.stackedWidget.setCurrentIndex(2))
self.products_window.button_previous.clicked.connect(
lambda: self.stackedWidget.setCurrentIndex(0))
self.input_prices_window = Input_Prices_Window()
self.input_prices_window.button_previous.clicked.connect(
lambda: self.stackedWidget.setCurrentIndex(1))
self.stackedWidget = QStackedWidget(self) # !!! +++
self.stackedWidget.addWidget(self.current_window)
self.stackedWidget.addWidget(self.products_window)
self.stackedWidget.addWidget(self.input_prices_window)
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.stackedWidget)
self.stackedWidget.setCurrentIndex(0)
StyleSheet = '''
#centralwidget {
background-color: #1E152A;
}
#heading {
font-size: 38px;
color: "#8FE381";
}
#button_calc, #button_next, #button_previous {
font-size: 30px;
color: "#837569";
letter-spacing: 4px;
border: 4px solid "#FFA9E7";
border-radius: 20px;
margin-bottom: 30px;
}
#button_next, #button_previous {
font-size: 20px;
border-radius: 15px;
}
#button_calc:hover, #button_next:hover, #button_previous:hover {
background: #FFA9E7;
color: #1E152A;
}
QCheckBox {
border: 1px solid #837569;
border-radius : 5px;
letter-spacing: 2px;
font-size: 15px;
font-weight: 600;
color: #837569;
margin-left: 50%;
letter-spacing: 2;
margin-right: 50%;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 20px;
}
#scrollArea, #scrollAreaWidgetContents {
border: 1px solid #837569;
border-radius: 20px;
background-color: #1E152A;
}
QLineEdit {
border: 1px solid #837569;
border-radius : 5px;
letter-spacing: 2px;
font-size: 15px;
font-weight: 600;
color: #837569;
background-color: #1E152A;
}
QLineEdit:focus {
outline: none !important;
border: 2px solid #837569;
border-radius: 5px;
background-color: #0E051A;
color: #938579;
}
'''
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setStyleSheet(StyleSheet)
window = Base()
window.resize(800, 600)
window.show()
sys.exit(app.exec_())


