I've been trying to mimic Windows' calculator using PyQt5
.
I reached a point where I needed to change the text's color that is on the QLabel
that I am using as a custom window border(to allow things such as transparency).
I started experimenting with things such as QEvent
and eventFilter
and using methods such as isActiveWindow
to try and switch between shades of black and between transparent color and non-transparent.
Doing so, I managed to get to a stage where the background changes perfectly, but the moment I try and add the QLabel/Text into the mix the program crashes at various points. I've been unable as of writing to figure out where or why and using the console just prints "Process finished with exit code -1073740791 (0xC0000409)".
Also, I couldn't find anything obvious for my current knowledge and experience as to why this is happening. So far YouTube, Google and existing StackOverflow content has let me down. :(
Please take into consideration I am extremely new to programming, Python and even more so PyQt5.
Thanks in advance,
-Omer
My full code:
# this program makes a simple(non-scientific) calculator
import os
import sys
from PyQt5 import QtCore
from PyQt5.QtCore import QObject, Qt, QEvent
from PyQt5.QtGui import QBrush, QFont, QIcon, QPalette, QPixmap, QRegion
from PyQt5.QtWidgets import QApplication, QDesktopWidget, QLabel, \
QMainWindow, \
QPushButton, QWidget
class Main(QApplication):
def __init__(self):
super(Main, self).__init__(sys.argv)
self.current_dir = os.getcwd()
self.current_dir = self.current_dir.replace('\\', '/')
self.background_palette = QPalette()
self.background_pixmap = QPixmap()
self.border_palette = QPalette()
self.border_pixmap = QPixmap()
self.background = Background(self.current_dir,
self.background_palette,
self.background_pixmap,
)
self.main_window = MainWindow(self.background,
self.current_dir,
self.background_palette,
self.background_pixmap)
self.border = Border(self.current_dir,
self.background,
self.main_window.window_width,
self.main_window.window_title,
self.border_palette,
self.border_pixmap)
self.display = Display(self.main_window)
self.buttons = Buttons(self.background, self.current_dir)
self.background.init_background()
self.border.init_border()
self.display.init_display()
self.buttons.init_buttons()
self.main_window.init_window()
self.focus_coloring = FocusColoring(self.background, self.border)
self.installEventFilter(self.focus_coloring)
self.end()
def end(self):
sys.exit(self.exec())
# create the calculator's window
class MainWindow(QMainWindow):
def __init__(self, background, current_dir, background_palette,
background_pixmap):
super(MainWindow, self).__init__()
self._window_geometry = self.frameGeometry()
self.desktop_center = QDesktopWidget().availableGeometry().center()
self.background = background
self.window_width = 322
self.window_height = 502
self.window_title = 'Calculator'
# set the current directory the script is running from to set a full
# path for things like images such as the
# window's icon
self.current_dir = current_dir
self.background_palette = background_palette
self.background_pixmap = background_pixmap
self.icon_path = '\\images\\icons\\calculator_icon.ico'
self.full_icon_path = self.current_dir + self.icon_path
def init_window(self):
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.resize(self.window_width, self.window_height)
self.setMinimumWidth(self.window_width)
self.setMaximumWidth(self.window_height)
# move the window to the center of the user's desktop
self._window_geometry.moveCenter(self.desktop_center)
self.move(self._window_geometry.topLeft())
self.setWindowTitle(self.window_title)
self.setWindowIcon(QIcon(self.full_icon_path))
self.setObjectName('QMainWindow')
self.setCentralWidget(self.background)
self.show()
class Border(QLabel):
def __init__(self, current_dir, parent, parent_width, parent_title,
border_palette,
border_pixmap):
super(Border, self).__init__(parent)
self.parent = parent
self.border_height = 30
self.border_width = parent_width
self.border_title = ' ' + parent_title
self.border_palette = border_palette
self.border_pixmap = border_pixmap
self.border_title_font = 'Arial'
self.border_title_font_size = 9
self.unfocused_background_path = '\\images\\backgrounds\\unfocused.png'
self.focused_background_path = '\\images\\backgrounds\\focused.png'
self.current_dir = current_dir
self.full_unfocused_path = \
self.current_dir + self.unfocused_background_path
self.full_focused_path = \
self.current_dir + self.focused_background_path
self.region = QRegion(self.border_pixmap.mask())
self.border_palette.setBrush(QPalette.Background, QBrush(
QPixmap(self.full_unfocused_path)))
def init_border(self):
self.setObjectName('QLabel')
self.resize(self.border_width, self.border_height)
self.setText(self.border_title)
self.setFont(QFont(
self.border_title_font,
self.border_title_font_size)
)
self.setPalette(self.border_palette)
self.setAutoFillBackground(True)
self.setMask(self.border_pixmap.mask())
class Background(QWidget):
def __init__(self, current_dir, background_palette,
background_pixmap):
super(Background, self).__init__()
self.unfocused_background_path = '\\images\\backgrounds\\unfocused.png'
self.focused_background_path = '\\images\\backgrounds\\focused.png'
self.current_dir = current_dir
self.background_palette = background_palette
self.background_pixmap = background_pixmap
self.full_unfocused_path = \
self.current_dir + self.unfocused_background_path
self.full_focused_path = \
self.current_dir + self.focused_background_path
self.region = QRegion(self.background_pixmap.mask())
self.background_palette.setBrush(QPalette.Background, QBrush(
QPixmap(self.full_unfocused_path)))
def init_background(self):
self.setAutoFillBackground(True)
self.setPalette(self.background_palette)
self.setMask(self.background_pixmap.mask())
class FocusColoring(QObject):
def __init__(self, background, label):
super(FocusColoring, self).__init__()
self.background = background
self.label = label
def change_background(self):
if self.background.isActiveWindow() is True:
print(self.background.isActiveWindow())
self.background.background_palette.setBrush(
QPalette.Background, QBrush(QPixmap(
self.background.full_focused_path)
))
self.background.init_background()
elif self.background.isActiveWindow() is False:
print(self.background.isActiveWindow())
self.background.background_palette.setBrush(
QPalette.Background, QBrush(QPixmap(
self.background.full_unfocused_path)
))
self.background.init_background()
def change_border(self):
if self.background.isActiveWindow() is True:
self.label.border_palette.setBrush(
QPalette.Background, QBrush(QPixmap(
self.label.full_focused_path)))
self.label.init_border()
elif self.background.isActiveWindow() is False:
print(self.background.isActiveWindow())
self.label.label_palette.setBrush(
QPalette.Background, QBrush(QPixmap(
self.background.full_unfocused_path)
))
self.label.init_border()
def eventFilter(self, obj, event):
if event.type() == QEvent.MouseButtonPress or \
QEvent.NonClientAreaMouseButtonPress:
self.change_background()
self.change_border()
return False
class Display(object):
def __init__(self, parent):
super(Display, self).__init__()
self.parent = parent
# readied to implement
def init_display(self):
pass
class Memory(QWidget):
def __init__(self, parent):
super(Memory, self).__init__(parent)
class Buttons(QWidget):
def __init__(self, parent, current_dir):
super(Buttons, self).__init__(parent)
self.width = 78
self.height = 51
self.parent = parent
self.posx = -abs(self.width)
self.posy = 196
self.original_posx = self.posx
self.original_posy = self.posy
self.setAttribute(Qt.WA_TranslucentBackground)
self.setWindowFlags(Qt.FramelessWindowHint)
self.buttons_dict = ['Remainder',
'CE',
'C',
'Backspace',
'Multiplicative Inverse',
'Power',
'Square Root',
'Division',
'7',
'8',
'9',
'Multiplication',
'4',
'5',
'6',
'Subtraction',
'1',
'2',
'3',
'Addition',
'Negation',
'0',
'Decimal',
'Equals']
self.current_dir = current_dir
self.buttons_path = self.current_dir + '/images/buttons'
self.remainder_default = self.buttons_path + '/remainder/default.png'
self.remainder_hover = self.buttons_path + '/remainder/hover.png'
self.remainder_pressed = self.buttons_path + '/remainder/pressed.png'
self.ce_default = self.buttons_path + '/ce/default.png'
self.ce_hover = self.buttons_path + '/ce/hover.png'
self.ce_pressed = self.buttons_path + '/ce/pressed.png'
self.ce = (self.ce_default,
self.ce_hover,
self.ce_pressed)
self.c_default = self.buttons_path + '/c/default.png'
self.c_hover = self.buttons_path + '/c/hover.png'
self.c_pressed = self.buttons_path + '/c/pressed.png'
self.backspace_default = self.buttons_path + '/backspace/default.png'
self.backspace_hover = self.buttons_path + '/backspace/hover.png'
self.backspace_pressed = self.buttons_path + '/backspace/pressed.png'
self.multi_inverse_default = self.buttons_path + \
'/multi_inverse/default.png'
self.multi_inverse_hover = self.buttons_path + \
'/multi_inverse/hover.png'
self.multi_inverse_pressed = self.buttons_path + \
'/multi_inverse/pressed.png'
self.power_default = self.buttons_path + '/power/default.png'
self.power_hover = self.buttons_path + '/power/hover.png'
self.power_pressed = self.buttons_path + '/power/pressed.png'
self.sqrt_default = self.buttons_path + '/sqrt/default.png'
self.sqrt_hover = self.buttons_path + '/sqrt/hover.png'
self.sqrt_pressed = self.buttons_path + '/sqrt/pressed.png'
self.division_default = self.buttons_path + '/division/default.png'
self.division_hover = self.buttons_path + '/division/hover.png'
self.division_pressed = self.buttons_path + '/division/pressed.png'
self.seven_default = self.buttons_path + '/seven/default.png'
self.seven_hover = self.buttons_path + '/seven/hover.png'
self.seven_pressed = self.buttons_path + '/seven/pressed.png'
self.eight_default = self.buttons_path + '/eight/default.png'
self.eight_hover = self.buttons_path + '/eight/hover.png'
self.eight_pressed = self.buttons_path + '/eight/pressed.png'
self.nine_default = self.buttons_path + '/nine/default.png'
self.nine_hover = self.buttons_path + '/nine/hover.png'
self.nine_pressed = self.buttons_path + '/nine/pressed.png'
self.multiply_default = self.buttons_path + '/multiply/default.png'
self.multiply_hover = self.buttons_path + '/multiply/hover.png'
self.multiply_pressed = self.buttons_path + '/multiply/pressed.png'
self.four_default = self.buttons_path + '/four/default.png'
self.four_hover = self.buttons_path + '/four/hover.png'
self.four_pressed = self.buttons_path + '/four/pressed.png'
self.five_default = self.buttons_path + '/five/default.png'
self.five_hover = self.buttons_path + '/five/hover.png'
self.five_pressed = self.buttons_path + '/five/pressed.png'
self.six_default = self.buttons_path + '/six/default.png'
self.six_hover = self.buttons_path + '/six/hover.png'
self.six_pressed = self.buttons_path + '/six/pressed.png'
self.subtract_default = self.buttons_path + '/subtract/default.png'
self.subtract_hover = self.buttons_path + '/subtract/hover.png'
self.subtract_pressed = self.buttons_path + '/subtract/pressed.png'
self.one_default = self.buttons_path + '/one/default.png'
self.one_hover = self.buttons_path + '/one/hover.png'
self.one_pressed = self.buttons_path + '/one/pressed.png'
self.two_default = self.buttons_path + '/two/default.png'
self.two_hover = self.buttons_path + '/two/hover.png'
self.two_pressed = self.buttons_path + '/two/pressed.png'
self.three_default = self.buttons_path + '/three/default.png'
self.three_hover = self.buttons_path + '/three/hover.png'
self.three_pressed = self.buttons_path + '/three/pressed.png'
self.addition_default = self.buttons_path + '/addition/default.png'
self.addition_hover = self.buttons_path + '/addition/hover.png'
self.addition_pressed = self.buttons_path + '/addition/pressed.png'
self.negate_default = self.buttons_path + '/negate/default.png'
self.negate_hover = self.buttons_path + '/negate/hover.png'
self.negate_pressed = self.buttons_path + '/negate/pressed.png'
self.zero_default = self.buttons_path + '/zero/default.png'
self.zero_hover = self.buttons_path + '/zero/hover.png'
self.zero_pressed = self.buttons_path + '/zero/pressed.png'
self.decimal_default = self.buttons_path + '/decimal/default.png'
self.decimal_hover = self.buttons_path + '/decimal/hover.png'
self.decimal_pressed = self.buttons_path + '/decimal/pressed.png'
self.equals_default = self.buttons_path + '/equals/default.png'
self.equals_hover = self.buttons_path + '/equals/hover.png'
self.equals_pressed = self.buttons_path + '/equals/pressed.png'
self.button_style = '''
QPushButton {{
margin: 1px;
border: 0px;
background-image: url({});
}}
QPushButton:hover {{
background-image: url({});
}}
QPushButton:pressed {{
background-image: url({});
}}
'''
def init_buttons(self):
for button_index, button in enumerate(self.buttons_dict):
self.buttons_dict[button_index] = QPushButton(self)
self.buttons_dict[button_index].setObjectName('QPushButton')
self.buttons_dict[button_index].resize(self.width, self.height)
self.posx += self.width
if self.posx == self.width * 4:
self.posy = self.posy + self.height - 1
self.posx = self.original_posx + self.width
self.buttons_dict[button_index].move(self.posx + 5, self.posy)
self.buttons_dict[button_index].setFlat(True)
self.buttons_dict[button_index].setAutoFillBackground(True)
self.buttons_dict[0].setStyleSheet(
self.button_style.format(self.remainder_default,
self.remainder_hover,
self.remainder_pressed)
)
self.buttons_dict[1].setStyleSheet(
self.button_style.format(self.ce_default,
self.ce_hover,
self.ce_pressed)
)
self.buttons_dict[2].setStyleSheet(
self.button_style.format(self.c_default,
self.c_hover,
self.c_pressed)
)
self.buttons_dict[3].setStyleSheet(
self.button_style.format(self.backspace_default,
self.backspace_hover,
self.backspace_pressed)
)
self.buttons_dict[4].setStyleSheet(
self.button_style.format(self.multi_inverse_default,
self.multi_inverse_hover,
self.multi_inverse_pressed)
)
self.buttons_dict[5].setStyleSheet(
self.button_style.format(self.power_default,
self.power_hover,
self.power_pressed)
)
self.buttons_dict[6].setStyleSheet(
self.button_style.format(self.sqrt_default,
self.sqrt_hover,
self.sqrt_pressed)
)
self.buttons_dict[7].setStyleSheet(
self.button_style.format(self.division_default,
self.division_hover,
self.division_pressed)
)
self.buttons_dict[8].setStyleSheet(
self.button_style.format(self.seven_default,
self.seven_hover,
self.seven_pressed)
)
self.buttons_dict[9].setStyleSheet(
self.button_style.format(self.eight_default,
self.eight_hover,
self.eight_pressed)
)
self.buttons_dict[10].setStyleSheet(
self.button_style.format(self.nine_default,
self.nine_hover,
self.nine_pressed)
)
self.buttons_dict[11].setStyleSheet(
self.button_style.format(self.multiply_default,
self.multiply_hover,
self.multiply_pressed)
)
self.buttons_dict[12].setStyleSheet(
self.button_style.format(self.four_default,
self.four_hover,
self.four_pressed)
)
self.buttons_dict[13].setStyleSheet(
self.button_style.format(self.five_default,
self.five_hover,
self.five_pressed)
)
self.buttons_dict[14].setStyleSheet(
self.button_style.format(self.six_default,
self.six_hover,
self.six_pressed)
)
self.buttons_dict[15].setStyleSheet(
self.button_style.format(self.subtract_default,
self.subtract_hover,
self.subtract_pressed)
)
self.buttons_dict[16].setStyleSheet(
self.button_style.format(self.one_default,
self.one_hover,
self.one_pressed)
)
self.buttons_dict[17].setStyleSheet(
self.button_style.format(self.two_default,
self.two_hover,
self.two_pressed)
)
self.buttons_dict[18].setStyleSheet(
self.button_style.format(self.three_default,
self.three_hover,
self.three_pressed)
)
self.buttons_dict[19].setStyleSheet(
self.button_style.format(self.addition_default,
self.addition_hover,
self.addition_pressed)
)
self.buttons_dict[20].setStyleSheet(
self.button_style.format(self.negate_default,
self.negate_hover,
self.negate_pressed)
)
self.buttons_dict[21].setStyleSheet(
self.button_style.format(self.zero_default,
self.zero_hover,
self.zero_pressed)
)
self.buttons_dict[22].setStyleSheet(
self.button_style.format(self.decimal_default,
self.decimal_hover,
self.decimal_pressed)
)
self.buttons_dict[23].setStyleSheet(
self.button_style.format(self.equals_default,
self.equals_hover,
self.equals_pressed)
)
if __name__ == '__main__':
main = Main()
User contributions licensed under CC BY-SA 3.0