Skip to content
Snippets Groups Projects
Commit 029b3a68 authored by Andreas Bolin's avatar Andreas Bolin
Browse files

Cleanup main_window.py. Fixed bug with sublass QObject in PyQt5

parent a79f8920
Branches
No related tags found
1 merge request!78Add scheduler GUI
Pipeline #73417 passed
......@@ -7,9 +7,10 @@ from logger import *
from main_window import *
from graphics_graph_item import *
from graphics_graph_event import *
from graphics_axis_item import *
from graphics_component_item import *
from graphics_axes_item import *
from graphics_timeline_item import *
# __all__ = ['main_window', 'graphics_graph', 'graphics_axis', 'component_item']
# __all__ = ['main_window', 'graphics_graph', 'component_item', 'graphics_axes', 'graphics_timeline_item']
__version__ = '0.1'
__author__ = 'Andreas Bolin'
......@@ -43,16 +43,22 @@ from graphics_timeline_item import GraphicsTimelineItem
sys.settrace
# class GraphicsGraphEvent(ABC):
class GraphicsGraphEvent(QGraphicsItemGroup, QObject):
# class GraphicsGraphEvent(QGraphicsObject):
# sys.settrace
# class GraphicsGraphEvent(QGraphicsItemGroup, QObject): # PySide2
class GraphicsGraphEvent(): # PyQt5
"""Event filter and handlers for GraphicsGraphItem"""
class Signals(QObject): # PyQt5
"""A class respresenting signals."""
component_selected = Signal(str)
schedule_time_changed = Signal()
_axes: GraphicsAxesItem
_current_pos: QPointF
_delta_time: int
component_selected = Signal(str)
schedule_time_changed = Signal()
signals: Signals # PyQt5
# component_selected = Signal(str) # PySide2
# schedule_time_changed = Signal() # PySide2
@overload
def is_component_valid_pos(self, pos: float, end_time: int) -> bool: ...
......@@ -61,12 +67,15 @@ class GraphicsGraphEvent(QGraphicsItemGroup, QObject):
@overload
def set_schedule_time(self, delta_time: int) -> None: ...
def __init__(self, parent: Optional[QGraphicsItem] = None):
QObject.__init__(self)
QGraphicsItemGroup.__init__(self, parent)
# QGraphicsObject.__init__(self)
# super().__init__(parent)
# super().__init__()
# def __init__(self, parent: Optional[QGraphicsItem] = None): # PySide2
# QObject.__init__(self)
# QGraphicsItemGroup.__init__(self, parent)
def __init__(self, parent: Optional[QGraphicsItem] = None): # PyQt5
# QGraphicsItemGroup.__init__(self, parent)
# QObject.__init__(self)
super().__init__()
self.signals = self.Signals()
#################
#### Filters ####
......@@ -187,7 +196,8 @@ class GraphicsGraphEvent(QGraphicsItemGroup, QObject):
by default be accepted, and this item is then the mouse grabber. This
allows the item to receive future move, release and double-click events."""
item: GraphicsComponentItem = self.scene().mouseGrabberItem()
self.component_selected.emit(item.op_id)
self.signals.component_selected.emit(item.op_id)
# self.component_selected.emit(item.op_id)
self._current_pos = item.mapToParent(event.pos())
item.setCursor(QCursor(Qt.ClosedHandCursor))
event.accept()
......@@ -248,5 +258,4 @@ class GraphicsGraphEvent(QGraphicsItemGroup, QObject):
item.hide_label()
if self._delta_time != 0:
self.set_schedule_time(self._delta_time)
self.schedule_time_changed.emit()
self.signals.schedule_time_changed.emit()
......@@ -47,7 +47,8 @@ from graphics_axes_item import GraphicsAxesItem
from graphics_graph_event import GraphicsGraphEvent
class GraphicsGraphItem(GraphicsGraphEvent, QGraphicsItemGroup):
# class GraphicsGraphItem(GraphicsGraphEvent, QGraphicsItemGroup): # PySide2 / PyQt5
class GraphicsGraphItem(QGraphicsItemGroup, GraphicsGraphEvent): # PyQt5
"""A class to represent a graph in a QGraphicsScene. This class is a
subclass of QGraphicsItemGroup and contains the objects, axes from
GraphicsAxesItem, as well as components from GraphicsComponentItem. It
......@@ -160,4 +161,4 @@ class GraphicsGraphItem(GraphicsGraphEvent, QGraphicsItemGroup):
# self._axes.update_axes(schedule_time - 2, self._components_height, self._x_axis_indent)
for component in self._components:
self.addToGroup(component)
# self.addToGroup(self._components)
\ No newline at end of file
# self.addToGroup(self._components)
......@@ -6,16 +6,12 @@ Contains the scheduler-gui MainWindow class for scheduling operations in an SFG.
Start main-window with start_gui().
"""
from copy import deepcopy
import os
import sys
from pathlib import Path
from types import ModuleType
from typing import Any, Iterable, List, Sequence, Type, Dict, Union
from pprint import pprint
#from matplotlib.pyplot import bar
#from diagram import *
from importlib.machinery import SourceFileLoader
from typing import Union
from pprint import pprint
from copy import deepcopy
from importlib.machinery import SourceFileLoader
import inspect
......@@ -26,18 +22,12 @@ from qtpy.QtCore import QCoreApplication, Qt, Slot, Signal, QSettings, QStand
from qtpy.QtGui import QCloseEvent
from qtpy.QtWidgets import (
QApplication, QMainWindow, QMessageBox, QFileDialog, QInputDialog, QCheckBox, QAbstractButton,
QTableWidgetItem, QSizePolicy)
QTableWidgetItem)
# QGraphics and QPainter imports
from qtpy.QtCore import (
QRect, QRectF, QPoint, QSize, QByteArray, QMarginsF, QObject)
from qtpy.QtGui import (
QPaintEvent, QPainter, QPainterPath, QColor, QBrush, QPen, QFont, QPolygon, QIcon, QPixmap,
QLinearGradient)
from qtpy.QtWidgets import (
QGraphicsView, QGraphicsScene, QGraphicsWidget, QGraphicsScale,
QGraphicsLayout, QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayoutItem, QGraphicsAnchorLayout,
QGraphicsItem, QGraphicsItemGroup, QGraphicsRectItem, QHeaderView)
from qtpy.QtCore import QRectF, QByteArray
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import QGraphicsScene, QGraphicsItemGroup
# B-ASIC
import logger
......@@ -59,7 +49,6 @@ sys.excepthook = logger.handle_exceptions
if __debug__:
log.setLevel('DEBUG')
if __debug__:
# Print some system version information
QT_API = os.environ.get('QT_API')
......@@ -102,7 +91,7 @@ sys.path.insert(0, 'icons/') # Needed for the compiled '*_rc.py'
from ui_main_window import Ui_MainWindow # Only availible when the form (.ui) is compiled
# The folowing QCoreApplication values is used for QSettings among others
# The following QCoreApplication values is used for QSettings among others
QCoreApplication.setOrganizationName('Linöping University')
QCoreApplication.setOrganizationDomain('liu.se')
QCoreApplication.setApplicationName('B-ASIC Scheduler')
......@@ -114,22 +103,21 @@ QCoreApplication.setApplicationName('B-ASIC Scheduler')
class MainWindow(QMainWindow, Ui_MainWindow):
"""Schedule of an SFG with scheduled Operations."""
_scene: QGraphicsScene
_schedule: Union[Schedule, None]
_graph: Union[GraphicsGraphItem, None]
_scale: float
_debug_rects: QGraphicsItemGroup
_splitter_pos: int
_splitter_min: int
_schedule: Union[Schedule, None]
def __init__(self):
"""Initialize Schedule-gui."""
"""Initialize Scheduler-gui."""
super().__init__()
self._schedule = None
self._graph = None
self._open_file_dialog_opened = False
self._scale = 75
self._scale = 75.0
self._debug_rects = None
self._schedule = None
QIcon.setThemeName('breeze')
log.debug('themeName: \'{}\''.format(QIcon.themeName()))
......@@ -149,9 +137,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.menu_save .triggered .connect(self.save)
self.menu_save_as .triggered .connect(self.save_as)
self.menu_quit .triggered .connect(self.close)
self.menu_node_info .triggered .connect(self.toggle_component_info)
self.menu_exit_dialog .triggered .connect(self.toggle_exit_dialog)
self.actionT .triggered .connect(self.actionTbtn)
self.menu_node_info .triggered .connect(self.show_info_table)
self.menu_exit_dialog .triggered .connect(self.hide_exit_dialog)
self.actionT .triggered .connect(self._actionTbtn)
self.splitter .splitterMoved .connect(self._splitter_moved)
# Setup event member functions
......@@ -181,6 +169,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
@property
def schedule(self) -> Schedule:
"""Get the current schedule."""
return self._schedule
......@@ -188,15 +177,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
#### Slots ####
###############
@Slot()
def actionTbtn(self) -> None:
def _actionTbtn(self) -> None:
# TODO: remove
self.schedule.plot_schedule()
print(f'filtersChildEvents(): {self._graph.filtersChildEvents()}')
# self.printButtonPressed('callback_pushButton()')
# self._printButtonPressed('callback_pushButton()')
@Slot()
def _load_schedule_from_pyfile(self) -> None:
"""SLOT() for SIGNAL(menu_load_from_file.triggered)
Load a python script as a module and search for a Schedule object. If
found, opens it."""
settings = QSettings()
# open_dir = QStandardPaths.standardLocations(QStandardPaths.HomeLocation)[0] if not self._open_file_dialog_opened else ''
last_file = settings.value('mainwindow/last_opened_file', QStandardPaths.standardLocations(QStandardPaths.HomeLocation)[0], str)
if not os.path.exists(last_file): # if filename does not exist
last_file = os.path.dirname(last_file) + '/'
......@@ -211,7 +203,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if not abs_path_filename: # return if empty filename (QFileDialog was canceled)
return
log.debug('abs_path_filename = {}.'.format(abs_path_filename))
self._open_file_dialog_opened = True
module_name = inspect.getmodulename(abs_path_filename)
if not module_name: # return if empty module name
......@@ -253,9 +244,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
@Slot()
def close_schedule(self) -> None:
"""SLOT() for SIGNAL(menu_close_schedule.triggered)
Closes current schedule."""
if self._graph:
self._graph.component_selected.disconnect(self.info_table_update_component)
self._graph.schedule_time_changed.disconnect(self.info_table_update_schedule)
self._graph.signals.component_selected.disconnect(self.info_table_update_component)
self._graph.signals.schedule_time_changed.disconnect(self.info_table_update_schedule)
self._graph.removeSceneEventFilters(self._graph.event_items)
self._scene.removeItem(self._graph)
self.menu_close_schedule.setEnabled(False)
......@@ -267,21 +260,25 @@ class MainWindow(QMainWindow, Ui_MainWindow):
@Slot()
def save(self) -> None:
"""This method save an schedule."""
"""SLOT() for SIGNAL(menu_save.triggered)
This method save an schedule."""
#TODO: all
self.printButtonPressed('save_schedule()')
self._printButtonPressed('save_schedule()')
self.update_statusbar(self.tr('Schedule saved successfully'))
@Slot()
def save_as(self) -> None:
"""This method save as an schedule."""
"""SLOT() for SIGNAL(menu_save_as.triggered)
This method save as an schedule."""
#TODO: all
self.printButtonPressed('save_schedule()')
self._printButtonPressed('save_schedule()')
self.update_statusbar(self.tr('Schedule saved successfully'))
@Slot(bool)
def toggle_component_info(self, checked: bool) -> None:
"""This method toggles the right hand side info window."""
def show_info_table(self, checked: bool) -> None:
"""SLOT(bool) for SIGNAL(menu_node_info.triggered)
Takes in a boolean and hide or show the info table accordingly with
'checked'."""
# Note: splitter handler index 0 is a hidden splitter handle far most left, use index 1
# settings = QSettings()
_, max = self.splitter.getRange(1) # tuple(min, max)
......@@ -295,13 +292,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.splitter.moveSplitter(max, 1)
@Slot(bool)
def toggle_exit_dialog(self, checked: bool) -> None:
def hide_exit_dialog(self, checked: bool) -> None:
"""SLOT(bool) for SIGNAL(menu_exit_dialog.triggered)
Takes in a boolean and stores 'checked' in 'hide_exit_dialog' item in
settings."""
s = QSettings()
s.setValue("mainwindow/hide_exit_dialog", checked)
@Slot(int, int)
def _splitter_moved(self, pos: int, index: int) -> None:
"""Callback method used to check if the right widget (info window)
"""SLOT(int, int) for SIGNAL(splitter.splitterMoved)
Callback method used to check if the right widget (info window)
has collapsed. Update the checkbutton accordingly."""
width = self.splitter.sizes()[1]
......@@ -315,7 +316,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
@Slot(str)
def info_table_update_component(self, op_id: str) -> None:
"""Taked in an operator-id, first clears the 'Operator' part of the info
"""SLOT(str) for SIGNAL(_graph.signals.component_selected)
Taked in an operator-id, first clears the 'Operator' part of the info
table and then fill in the table with new values from the operator
associated with 'op_id'."""
self.info_table_clear_component()
......@@ -323,11 +325,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
@Slot()
def info_table_update_schedule(self) -> None:
"""Updates the 'Schedule' part of the info table."""
"""SLOT() for SIGNAL(_graph.signals.schedule_time_changed)
Updates the 'Schedule' part of the info table."""
self.info_table.item(1, 1).setText(str(self.schedule.schedule_time))
@Slot(QRectF)
def shrink_scene_to_min_size(self, rect: QRectF) -> None:
"""SLOT(QRectF) for SIGNAL(_scene.sceneRectChanged)
Takes in a QRectF (unused) and shrink the scene bounding rectangle to
it's minimum size, when the bounding rectangle signals a change in
geometry."""
self._scene.setSceneRect(self._scene.itemsBoundingRect())
......@@ -336,7 +343,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
#### Events ####
################
def _close_event(self, event: QCloseEvent) -> None:
"""Replaces QMainWindow default closeEvent(QCloseEvent) event"""
"""EVENT: Replaces QMainWindow default closeEvent(QCloseEvent) event. Takes
in a QCloseEvent and display an exit dialog, depending on
'hide_exit_dialog' in settings."""
s = QSettings()
hide_dialog = s.value('mainwindow/hide_exit_dialog', False, bool)
ret = QMessageBox.StandardButton.Yes
......@@ -370,7 +379,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
#################################
#### Helper member functions ####
#################################
def printButtonPressed(self, func_name: str) -> None:
def _printButtonPressed(self, func_name: str) -> None:
#TODO: remove
alert = QMessageBox(self)
......@@ -386,14 +395,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.menu_close_schedule.setEnabled(True)
self._scene.addItem(self._graph)
self._graph.installSceneEventFilters(self._graph.event_items)
self._graph.component_selected.connect(self.info_table_update_component)
self._graph.schedule_time_changed.connect(self.info_table_update_schedule)
self._graph.signals.component_selected.connect(self.info_table_update_component)
self._graph.signals.schedule_time_changed.connect(self.info_table_update_schedule)
self.info_table_fill_schedule(self.schedule)
self.update_statusbar(self.tr('Schedule loaded successfully'))
def update_statusbar(self, msg: str) -> None:
"""Write the given str to the statusbar with temporarily policy."""
"""Takes in an str and write 'msg' to the statusbar with temporarily policy."""
self.statusbar.showMessage(msg)
def _write_settings(self) -> None:
......@@ -475,7 +483,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
row = self.info_table.findItems('Operator', Qt.MatchExactly)
if row:
row = row[0].row()
if row > 1:
if row > 2:
for _ in range(3):
self.info_table.removeRow(1)
else:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment