class View(QGraphicsView): def __init__(self): super().__init__() self.setGeometry(300, 300, 300, 300) self.setRenderHint(QPainter.Antialiasing) self.init() def init(self): self.scene = QGraphicsScene() r1 = self.scene.addRect(150, 40, 100, 100) r1.setBrush(QColor(250, 50, 0)) r1.setPen(QColor(250, 50, 0)) el = self.scene.addEllipse(40, 70, 80, 80) el.setBrush(QColor(0, 50, 250)) el.setPen(QColor(0, 50, 250)) r2 = self.scene.addRect(60, 180, 150, 70) r2.setBrush(QColor(0, 250, 50)) r2.setPen(QColor(0, 250, 50)) self.setScene(self.scene)
def setupGUI(self): tabmain = QTabWidget() self.setCentralWidget(tabmain) # GPS Converter widget = QWidget() mainLayout = QGridLayout() widget.setLayout(mainLayout) self.openButton = self.createButton("Open Files", self.openFileClicked) mainLayout.addWidget(self.openButton, 0, 0) self.listWidget = QListWidget() mainLayout.addWidget(self.listWidget, 2, 0, 1, 2) self.runConvButton = self.createButton("Run Conversion", self.runConversionClicked) mainLayout.addWidget(self.runConvButton, 0, 1) self.runConvButton.setEnabled(False) self.multiCheckbox = self.createCheckbox("Multiple Markers per Map") mainLayout.addWidget(self.multiCheckbox, 1, 1) tabmain.addTab(widget, "GPS Data Conversion") # GPS View gpswidget = QWidget() gpsLayout = QGridLayout() gpswidget.setLayout(gpsLayout) gview = QGraphicsView() scene = QGraphicsScene() gview.setScene(scene) gpsLayout.addWidget(gview) blueBrush = QBrush(Qt.blue) mypen = QPen(Qt.black) scene.addRect(100, 0, 80, 100, mypen, blueBrush) tabmain.addTab(gpswidget, "GPS Visualisation")
class Altimeter_Tape(QGraphicsView): def __init__(self, parent=None): super(Altimeter_Tape, self).__init__(parent) self.setStyleSheet("border: 0px") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setRenderHint(QPainter.Antialiasing) self.setFocusPolicy(Qt.NoFocus) self._altimeter = 0 def resizeEvent(self, event): w = self.width() h = self.height() self.pph = 0.5 f = QFont() f.setPixelSize(20) fontMetrics = QFontMetricsF(f) height_pixel = 5000 + h dialPen = QPen(QColor(Qt.white)) dialPen.setWidth(2) self.scene = QGraphicsScene(0, 0, w, height_pixel) self.scene.addRect(0, 0, w, height_pixel, QPen(QColor(Qt.black)), QBrush(QColor(Qt.black))) for i in range(100, -1, -1): if i % 2 == 0: self.scene.addLine(w / 2 + 15, (-i * 50) + 5000 + h / 2, w, (-i * 50) + 5000 + h / 2, dialPen) t = self.scene.addText(str(i * 100)) t.setFont(f) self.scene.setFont(f) t.setDefaultTextColor(QColor(Qt.white)) t.setX(0) t.setY(((-i * 50) + 5000 + h / 2) - t.boundingRect().height() / 2) else: self.scene.addLine(w / 2 + 30, (-i * 50) + 5000 + h / 2, w, (-i * 50) + 5000 + h / 2, dialPen) self.setScene(self.scene) def redraw(self): self.resetTransform() self.centerOn(self.scene.width() / 2, -self._altimeter * self.pph + 5000 + self.height() / 2) def getAltimeter(self): return self._altimeter def setAltimeter(self, altimeter): print(altimeter) if altimeter != self._altimeter: self._altimeter = altimeter self.redraw() altimeter = property(getAltimeter, setAltimeter)
def main(argv): signal.signal(signal.SIGINT, signal.SIG_DFL) app = QApplication([]) scene = QGraphicsScene() view = QGraphicsView() thumbnails = [] for filename in os.listdir(argv[1]): filename = os.path.join(argv[1], filename) print(filename) thumbnails.append(DBusThumbnailer.thumbnail_from_filename(filename, "large")) count = 0 items = [] for y in range(0, 100000, 150): for x in range(0, 2500, 150): scene.addRect(x, y, 128, 128) # image = QImage(128, 128, QImage.Format_RGB32) if count < len(thumbnails): print(thumbnails[count]) image = QImage(thumbnails[count]) else: arr = numpy.random.randint(0, 2**32, (128, 128), dtype=numpy.uint32) image = QImage(arr, 128, 128, 128 * 4, QImage.Format_ARGB32) pixmap = QPixmap.fromImage(image) item = QGraphicsPixmapItem(pixmap) scene.addItem(item) text = scene.addText("Test Textual: {}".format(count)) item.setPos(x, y) text.setPos(x, y + 128) count += 1 item.setFlags(QGraphicsItem.ItemIsSelectable) item.setAcceptHoverEvents(True) items.append([item, text]) print(count) if False: random.shuffle(items) i = 0 for y in range(0, 100000, 150): for x in range(0, 2500, 150): for item in items[i]: item.setPos(x, y) i += 1 view.setScene(scene) view.resize(800, 600) view.show() app.exec()
def __init__(self): super().__init__() self.timerId = 0 size = self.size() width_border = SCREEN_HEIGHT_BORDER height_border = SCREEN_HEIGHT_BORDER board_start_x = 2 board_start_y = 2 board_width = (size.width() - width_border) / 4 * 3 board_height = size.height() - height_border x = board_start_x y = board_start_y x_diff = int((board_width - 2 * x) / 8) y_diff = int((board_height - 2 * y) / 8) scene = QGraphicsScene(self) view = QGraphicsView(scene) scene.setItemIndexMethod(QGraphicsScene.NoIndex) # scene.setSceneRect(-900, -900, 900, 900) scene.setSceneRect(scene.itemsBoundingRect()) # scene.setSceneRect(QRectF(0, 0, 3000, 2400)) view.setSceneRect(scene.sceneRect()) self.setScene(scene) self.setCacheMode(QGraphicsView.CacheBackground) self.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) self.setRenderHint(QPainter.Antialiasing) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorViewCenter) corn_silk_color = QColor(255, 248, 220) saddle_brown_color = QColor(139, 69, 19) antique_white_color = QColor(250, 235, 215) scene.addRect(0, 0, 50, 50, corn_silk_color) scene.addRect(110, 110, 50, 50, saddle_brown_color) scene.addRect(50, 50, 90, 90, saddle_brown_color) scene.addRect(x, y, board_width - x, board_height - y, corn_silk_color) board = Board() for fields_row in reversed(board.fields): for field in fields_row: field_color = antique_white_color if ( field.c + field.r) % 2 else saddle_brown_color scene.addRect(x, y, x_diff, y_diff, field_color) x += x_diff y += y_diff x = board_start_x node1 = Node(self) scene.addItem(node1) node1.setPos(-210, -520) self.scale(0.8, 0.8) self.setMinimumSize(400, 400) self.setWindowTitle("Elastic Nodes")
def paint(self, img): pixmap = cv233io.to_QPixmap(img) scene = QGraphicsScene(self) scene.addPixmap(pixmap) rect = QRectF(pixmap.rect()) if img is self.img: scene.addRect(rect, QPen(Qt.black, 3, Qt.SolidLine, Qt.SquareCap)) else: scene.addRect(rect, QPen(Qt.red, 3, Qt.DashLine, Qt.SquareCap)) scene.setSceneRect(rect) self.graphicsView.setScene(scene) self.paintHist(img)
def InitWindow(self): self.button1 = QPushButton("Rotate - ", self) self.button1.setGeometry(200,420,100,50) self.button1.clicked.connect(self.rotateMinus) self.button2 = QPushButton("Rotate +", self) self.button2.setGeometry(400,420,100,50) self.button2.clicked.connect(self.rotatePlus) scene = QGraphicsScene(self) redBrush = QBrush(Qt.red) blueBrush = QBrush(Qt.blue) blackPen = QPen(Qt.black) blackPen.setWidth(7) ellipse = scene.addEllipse(10,10,200,200, blackPen, redBrush) rect = scene.addRect(-100,-100,200,200, blackPen, blueBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) # set it to movable rect.setFlag(QGraphicsItem.ItemIsMovable) self.view = QGraphicsView(scene, self) self.view.setGeometry(0,0,680,400) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) self.setWindowIcon(QtGui.QIcon('./icon/icon.png')) self.show()
def InitWindow(self): self.button1 = QPushButton("Rotate - ", self) self.button1.setGeometry(200, 420, 100, 50) self.button1.clicked.connect(self.rotateminus) self.button2 = QPushButton("Rotate +", self) self.button2.setGeometry(320, 420, 100, 50) self.button2.clicked.connect(self.rotateplus) scene = QGraphicsScene() #the scene redbrush = QBrush(Qt.red) bluebrush = QBrush(Qt.blue) blackpen = QPen(Qt.black) blackpen.setWidth(7) ellipse = scene.addEllipse(10, 10, 200, 200, blackpen, redbrush) rect = scene.addRect(-100, -100, 200, 200, blackpen, bluebrush) line = scene.addLine(-100, -100, 200, 200, blackpen) ellipse.setFlag(QGraphicsItem.ItemIsMovable) rect.setFlag(QGraphicsItem.ItemIsMovable) line.setFlag(QGraphicsItem.ItemIsMovable) self.view = QGraphicsView(scene, self) self.view.setGeometry(0, 0, 680, 400) self.setWindowIcon(QtGui.QIcon("mongol.jpg")) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) self.show()
def __init__(self, parent) -> None: """ CONSTRUCTOR """ super().__init__(parent) self.ui = frm_lego_designer.Ui_Dialog(self) self.setWindowTitle("Lego Diagram Editor") # # Graphics view # self.ctrl_graphics_view = InteractiveGraphicsView() v = self.ctrl_graphics_view sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHeightForWidth(v.sizePolicy().hasHeightForWidth()) v.setSizePolicy(sizePolicy) v.setObjectName("graphicsView") v.setBackgroundBrush(QBrush(QColor(255, 255, 255))) v.setInteractive(True) layout = QGridLayout() self.ui.FRA_MAIN.setLayout(layout) layout.addWidget(v) # Open GL rendering if groot.data.config.options().opengl: v.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers))) # Default (empty) scene scene = QGraphicsScene() scene.addRect(QRectF(-10, -10, 20, 20)) v.setScene(scene) # # Create our model view! # self.model_view: ModelView = None self.update_view() self.toggle_show_edit(False) # Button clicks for x in (self.ui.BTN_S_EDGES_, self.ui.BTN_S_COMPS_, self.ui.BTN_S_GENES_, self.ui.BTN_S_MINCOMPS_, self.ui.BTN_S_DOMAINS_): x.clicked[bool].connect(self.on_btn_click)
class MainScreen(QMainWindow): def __init__(self): super().__init__() #self.setupUi(self) # Graphic Screen set self.img = QGraphicsPixmapItem(QPixmap('KarlaOnMyShoulder.jpg')) self.scene = QGraphicsScene() self.graphicsView = QGraphicsView() self.scene.addItem(self.img) self.graphicsView.setScene(self.scene) # Full Screen set size _WIDTH_ADD = 25 _HEIGHT_ADD = 25 self.setGeometry(0, 0, 640 + _WIDTH_ADD, 500 + _HEIGHT_ADD) self.graphicsView.viewport().installEventFilter(self) self.current_item = None self.start_pos = QPointF() self.end_pos = QPointF() self.show() def eventFilter(self, o, e): if self.graphicsView.viewport() is o: if e.type() == QEvent.MouseButtonPress: if e.buttons() & Qt.LeftButton: print("press") self.start_pos = self.end_pos = self.graphicsView.mapToScene( e.pos()) pen = QPen(QColor(240, 240, 240)) pen.setWidth(3) brush = QBrush(QColor(100, 255, 100, 100)) self.current_item = self.scene.addRect( QRectF(), pen, brush) self._update_item() elif e.type() == QEvent.MouseMove: if e.buttons( ) & Qt.LeftButton and self.current_item is not None: print("move") self.end_pos = self.graphicsView.mapToScene(e.pos()) self._update_item() elif e.type() == QEvent.MouseButtonRelease: print("release") self.end_pos = self.graphicsView.mapToScene(e.pos()) self._update_item() self.current_item = None return super().eventFilter(o, e) def _update_item(self): if self.current_item is not None: self.current_item.setRect( QRectF(self.start_pos, self.end_pos).normalized())
def initUi(self): layout = QGridLayout() graphics_view = QGraphicsView() layout.addWidget(graphics_view) width = graphics_view.frameGeometry().width() height = graphics_view.frameGeometry().height() scene = QGraphicsScene() scene.setSceneRect(0.0, 0.0, float(width), float(height)) scene.addRect(100, 100, 150, 150) pen = QPen(Qt.SolidLine) pen.setColor(Qt.red) brush = QBrush(Qt.Dense3Pattern) brush.setColor(Qt.darkGreen) scene.addEllipse(300, 300, 100, 100, pen, brush) graphics_view.setScene(scene) self.setLayout(layout)
def init(self): scene = QGraphicsScene() redBrush = QBrush(Qt.red) blueBrush = QBrush(Qt.blue) blackPen = QPen(Qt.black) blackPen.setWidth(7) ellipse = scene.addEllipse(10, 10, 200, 200, blackPen, redBrush) rectange = scene.addRect(-100, -100, 200, 200, blackPen, blueBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) #使图像可移动 rectange.setFlag(QGraphicsItem.ItemIsMovable) self.graphicsView.setScene(scene) self.graphicsView.scale(1.2, -1.2)
class Window(QMainWindow): def __init__(self): super().__init__() self.title = "PyQt5 QGraphicView" self.top = 200 self.left = 500 self.width = 600 self.height = 500 self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon("icon.png")) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.createGraphicView() self.show() def createGraphicView(self): self.scene = QGraphicsScene() self.greenBrush = QBrush(Qt.green) self.grayBrush = QBrush(Qt.gray) self.pen = QPen(Qt.red) graphicView = QGraphicsView(self.scene, self) graphicView.setGeometry(0, 0, 600, 500) self.shapes() def shapes(self): ellipse = self.scene.addEllipse(20, 20, 200, 200, self.pen, self.greenBrush) rect = self.scene.addRect(-100, -100, 200, 200, self.pen, self.grayBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) rect.setFlag(QGraphicsItem.ItemIsMovable) ellipse.setFlag(QGraphicsItem.ItemIsSelectable)
def InitWindow(self): scene = QGraphicsScene(self) redBrush = QBrush(Qt.red) blueBrush = QBrush(Qt.blue) blackPen = QPen(Qt.black) blackPen.setWidth(7) ellipse = scene.addEllipse(10, 10, 200, 200, blackPen, redBrush) rect = scene.addRect(-100, -100, 200, 200, blackPen, blueBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) # set it to movable rect.setFlag(QGraphicsItem.ItemIsMovable) view = QGraphicsView(scene, self) view.setGeometry(0, 0, 680, 500) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) self.setWindowIcon(QtGui.QIcon('./icon/icon.png')) self.show()
def main(args): # pragma: no cover from PyQt5.QtWidgets import QApplication app = QApplication(args) view = StickyGraphicsView() scene = QGraphicsScene(view) scene.setBackgroundBrush(QBrush(Qt.lightGray, Qt.CrossPattern)) view.setScene(scene) scene.addRect(QRectF(0, 0, 300, 20), Qt.red, QBrush(Qt.red, Qt.BDiagPattern)) scene.addRect(QRectF(0, 25, 300, 100)) scene.addRect(QRectF(0, 130, 300, 20), Qt.darkGray, QBrush(Qt.darkGray, Qt.BDiagPattern)) view.setHeaderSceneRect(QRectF(0, 0, 300, 20)) view.setFooterSceneRect(QRectF(0, 130, 300, 20)) view.show() return app.exec()
def main(args): # pragma: no cover # pylint: disable=import-outside-toplevel,protected-access from PyQt5.QtWidgets import QApplication, QAction from PyQt5.QtGui import QKeySequence app = QApplication(args) view = StickyGraphicsView() scene = QGraphicsScene(view) scene.setBackgroundBrush(QBrush(Qt.lightGray, Qt.CrossPattern)) view.setScene(scene) scene.addRect(QRectF(0, 0, 300, 20), Qt.red, QBrush(Qt.red, Qt.BDiagPattern)) scene.addRect(QRectF(0, 25, 300, 100)) scene.addRect(QRectF(0, 130, 300, 20), Qt.darkGray, QBrush(Qt.darkGray, Qt.BDiagPattern)) view.setHeaderSceneRect(QRectF(0, 0, 300, 20)) view.setFooterSceneRect(QRectF(0, 130, 300, 20)) view.show() zoomin = QAction("Zoom in", view, shortcut=QKeySequence.ZoomIn) zoomout = QAction("Zoom out", view, shortcut=QKeySequence.ZoomOut) zoomreset = QAction("Reset", view, shortcut=QKeySequence(Qt.ControlModifier | Qt.Key_0)) view._zoom = 100 def set_zoom(zoom): if view._zoom != zoom: view._zoom = zoom view.setTransform(QTransform.fromScale(*(view._zoom / 100, ) * 2)) zoomout.setEnabled(zoom >= 20) zoomin.setEnabled(zoom <= 300) @zoomin.triggered.connect def _(): set_zoom(view._zoom + 10) @zoomout.triggered.connect def _(): set_zoom(view._zoom - 10) @zoomreset.triggered.connect def _(): set_zoom(100) view.addActions([zoomin, zoomout, zoomreset]) return app.exec()
class MyGraphicsView(QGraphicsView): def __init__(self, central_widget): super().__init__(central_widget) self.widget = central_widget self.start = [0, 0] self.end = [0, 0] self.my_scene = QGraphicsScene() self.rect = QRectF() self.old_rect_item = None self.old_img_item = None self.drawing = False def mousePressEvent(self, event): self.start = [event.x(), event.y()] self.drawing = True def mouseMoveEvent(self, event): if not self.drawing: return self.end = [event.x(), event.y()] temp_start = [min(self.start[0], self.end[0]), min(self.start[1], self.end[1])] temp_end = [max(self.start[0], self.end[0]), max(self.start[1], self.end[1])] if self.old_rect_item: self.my_scene.removeItem(self.old_rect_item) self.rect.setRect(temp_start[0], temp_start[1], temp_end[0] - temp_start[0], temp_end[1] - temp_start[1]) self.old_rect_item = self.my_scene.addRect(self.rect, QPen(Qt.red, 1, Qt.SolidLine)) self.setScene(self.my_scene) # 释放鼠标 def mouseReleaseEvent(self, event): print('start:[{}, {}]'.format(self.start[0], self.start[1])) print('end:[{}, {}]'.format(self.end[0], self.end[1])) print(self.rect.getRect()) self.drawing = False
class PegBoard(QWidget): def __init__(self): super().__init__() self.region_x = 1000 self.region_y = 1000 self.scene = QGraphicsScene() self.setMouseTracking(True) self.board = None self.initUI() def initUI(self): self.setGeometry(500, 500, 500, 500) #TODO: will generate random board fields def generate_board(self): x = random.randint(0, self.region_x) y = random.randint(0, self.region_y) board = [[0]*x for _ in range(y)] def populate_board(self, matrix): rectangles = [[None]*7 for _ in range(7)] for row_index, row_value in enumerate(matrix): for column_index, column_value in enumerate(row_value): rec = Rectangle(100*row_index, 100*column_index, 100, 100) if column_value == 1: rec.state = 1 rectangles[row_index][column_index] = rec self.scene.addRect(rec.x, rec.y, rec.w, rec.h, rec.pen, rec.brushOn) elif column_value == 0: rec.state == 0 rectangles[row_index][column_index] = rec self.scene.addRect(rec.x, rec.y, rec.w, rec.h, rec.pen, rec.brushOff) else: rec.state = -1 rectangles[row_index][column_index] = rec self.scene.addRect(rec.x, rec.y, rec.w, rec.h, rec.pen, rec.brushOff) return rectangles
def test(self): view = StickyGraphicsView() scene = QGraphicsScene(view) scene.setBackgroundBrush(QBrush(Qt.lightGray, Qt.CrossPattern)) view.setScene(scene) scene.addRect(QRectF(0, 0, 300, 20), Qt.red, QBrush(Qt.red, Qt.BDiagPattern)) scene.addRect(QRectF(0, 25, 300, 100)) scene.addRect(QRectF(0, 130, 300, 20), Qt.darkGray, QBrush(Qt.darkGray, Qt.BDiagPattern)) view.setHeaderSceneRect(QRectF(0, 0, 300, 20)) view.setFooterSceneRect(QRectF(0, 130, 300, 20)) header = view.headerView() footer = view.footerView() view.resize(310, 310) view.grab() self.assertFalse(header.isVisibleTo(view)) self.assertFalse(footer.isVisibleTo(view)) view.resize(310, 100) view.verticalScrollBar().setValue(0) # scroll to top view.grab() self.assertFalse(header.isVisibleTo(view)) self.assertTrue(footer.isVisibleTo(view)) view.verticalScrollBar().setValue( view.verticalScrollBar().maximum()) # scroll to bottom view.grab() self.assertTrue(header.isVisibleTo(view)) self.assertFalse(footer.isVisibleTo(view)) qWheelScroll(header.viewport(), angleDelta=QPoint(0, -720 * 8))
class Ui_MainWindow(object): def setupUi(self, MainWindow): self.newDetectionAvailable = False MainWindow.setObjectName("MainWindow") MainWindow.resize(820, 620) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.dropdown_menu = QComboBox(self.centralwidget) font = QtGui.QFont() font.setPointSize(20) self.dropdown_menu.setFont(font) self.dropdown_menu.setGeometry(QtCore.QRect(540, 540, 240, 50)) self.robot_index = 0 for name_ip in NAME_IP_LIST: text = name_ip[0] + ': ' + name_ip[1] self.dropdown_menu.addItem(text) self.ip_addr = NAME_IP_LIST[0][1] self.server_running = True self.server_thread = threading.Thread(target=self.server) self.server_thread.start() font = QtGui.QFont() font.setPointSize(20) self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget) self.graphicsView.setGeometry(QtCore.QRect(10, 10, 800, 431)) self.graphicsView.setObjectName("graphicsView") self.StandardButton = QtWidgets.QPushButton(self.centralwidget) self.StandardButton.setGeometry(QtCore.QRect(60, 470, 170, 60)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.StandardButton.sizePolicy().hasHeightForWidth()) self.StandardButton.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setPointSize(20) self.StandardButton.setFont(font) self.StandardButton.setObjectName("StandardButton") self.AdvancedButton = QtWidgets.QPushButton(self.centralwidget) self.AdvancedButton.setGeometry(QtCore.QRect(570, 470, 170, 60)) font = QtGui.QFont() font.setPointSize(20) self.AdvancedButton.setFont(font) self.AdvancedButton.setObjectName("AdvancedButton") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.LCD = QLCDNumber(self.centralwidget) self.LCD.setGeometry(QtCore.QRect(350, 480, 100, 40)) self.LCD.display(0) self.LCD.setStyleSheet( 'QLCDNumber {background-color: green; color: red;}') self.clockLCD = QLCDNumber(self.centralwidget) self.clockLCD.setGeometry(QtCore.QRect(350, 540, 100, 40)) self.clockLCD.display('3:00') self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: yellow; color: red;}') self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) greenBrush = QBrush(Qt.green) #2 single healthy yellowBrush = QBrush(Qt.yellow) #1 single stressed whiteBrush = QBrush(Qt.white) #0 empty blueBrush = QBrush(Qt.blue) #3 double pinkBrush = QBrush(Qt.magenta) #4 tiller self.blackPen = QPen(Qt.black) self.BrushList = [ whiteBrush, yellowBrush, greenBrush, blueBrush, pinkBrush, QBrush(Qt.black) ] self.colorNames = [ 'Empty', 'Stressed', 'Healthy', 'Double', 'Tiller', 'Detection' ] self.level = 0 #standard self.newDetectionAvailable = False self.detectedFieldConfig = 5 * np.ones((4, 16), dtype=np.int8) self.fieldConfig = self.randFieldConfig() self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.AdvancedButton.clicked.connect(self.AdvBtnClickedSlot) self.StandardButton.clicked.connect(self.StdBtnClickedSlot) self.StdBtnClickedSlot() self.drawPlants() self.drawing_timer = QTimer() self.drawing_timer.setInterval(50) self.drawing_timer.timeout.connect(self.updateDetectionResult) self.drawing_timer.start() self.clock_seconds = 0 self.timestamp = '0:00' self.clock_timer = QTimer() self.clock_timer.setInterval(1000) self.clock_timer.timeout.connect(self.updateClock) self.clock_timer.start() self.time_is_up = False app.aboutToQuit.connect(self.closeEvent) def updateClock(self): if self.clock_seconds >= 300: if self.clock_seconds % 2 == 0: self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: yellow; color: red;}') else: self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: white; color: red;}') self.clockLCD.display('5:00') self.time_is_up = True else: self.timestamp = str(self.clock_seconds // 60) + ':' sec = self.clock_seconds % 60 self.timestamp += '0' + str(sec) if sec < 10 else str(sec) self.clockLCD.display(self.timestamp) self.clock_seconds += 1 def updateDetectionResult(self): if self.newDetectionAvailable: self.drawPlants() self.newDetectionAvailable = False def closeEvent(self): self.server_running = False self.server_thread.join() def server(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('', PORT)) while self.server_running: try: s.settimeout(1) s.listen(1) c, addr = s.accept() if addr[0] != self.ip_addr: c.close() continue with c: while self.server_running: try: c.settimeout(5) msg = c.recv(1024) if len(msg) != 64: c.close() print('invalid msg') break if not self.time_is_up: text = msg.decode('utf-8') self.detectedFieldConfig = np.reshape( np.array(list(text), dtype=np.int8), (4, 16)) upper_limit = 3 if self.level == 0 else 5 self.detectedFieldConfig[ (self.detectedFieldConfig < 0) | (self.detectedFieldConfig >= upper_limit)] = 5 self.newDetectionAvailable = True #f = open("log.txt", "a") #f.write(self.ip_addr+','+self.timestamp+','+msg) #f.close() except socket.timeout: print('client stopped sending updates') c.close() break except socket.error as exc: print(exc) c.close() break except socket.timeout: pass s.close() def drawPlants(self): size = 20 hor_space = 40 ver_space = 100 self.scene.clear() for y in range(4): for x in range(16): plant_type = self.fieldConfig.item((y, x)) r = QtCore.QRectF(QtCore.QPointF(x * hor_space, y * ver_space), QtCore.QSizeF(size, size)) self.scene.addRect(r, self.blackPen, self.BrushList[plant_type]) detected_plant_type = self.detectedFieldConfig.item((y, x)) self.scene.addEllipse(x * hor_space, y * ver_space + 30, size, size, self.blackPen, self.BrushList[detected_plant_type]) # separation line self.scene.addLine( QtCore.QLineF(16.4 * hor_space, 0, 16.4 * hor_space, 350)) # draw a legend for i in range(3 if self.level == 0 else 5): r = QtCore.QRectF( QtCore.QPointF(17 * hor_space, i * ver_space / 2), QtCore.QSizeF(size, size)) self.scene.addRect(r, self.blackPen, self.BrushList[i]) t = self.scene.addText(self.colorNames[i], QFont("Helvetica")) t.setPos(18 * hor_space, i * ver_space / 2) i = 3 if self.level == 0 else 5 self.scene.addEllipse(17 * hor_space, i * ver_space / 2, size, size, self.blackPen, self.BrushList[5]) t = self.scene.addText(self.colorNames[5], QFont("Helvetica")) t.setPos(18 * hor_space, i * ver_space / 2) #calculate the score true_count_per_row = np.count_nonzero( np.logical_and(self.fieldConfig > 0, self.fieldConfig < 5), axis=1) + np.count_nonzero(self.fieldConfig == 3, axis=1) robot_count_per_row = np.count_nonzero( np.logical_and(self.detectedFieldConfig > 0, self.detectedFieldConfig < 5), axis=1) + np.count_nonzero(self.detectedFieldConfig == 3, axis=1) # plant density score error_per_row = np.abs(true_count_per_row - robot_count_per_row) density_score = np.zeros(4, dtype=np.int32) density_score[error_per_row == 0] = 5 density_score[error_per_row == 1] = 3 density_score[error_per_row == 2] = 1 correct_detections = self.fieldConfig[np.equal( self.fieldConfig, self.detectedFieldConfig)] points_for_empty_or_stress = 3 if self.level == 0 else 2 detection_score = points_for_empty_or_stress * len( correct_detections[(correct_detections == 0) | (correct_detections == 1)]) if self.level == 1: detection_score += 4 * len( correct_detections[(correct_detections == 3) | (correct_detections == 4)]) print(detection_score, density_score.sum()) score = detection_score + density_score.sum() self.LCD.display(score) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle( _translate("MainWindow", "2020 ASABE Robotics Competition")) self.StandardButton.setText(_translate("MainWindow", "Standard")) self.AdvancedButton.setText(_translate("MainWindow", "Advanced")) def initialize(self): self.fieldConfig = self.randFieldConfig() self.drawPlants() self.server_running = False self.server_thread.join() self.ip_addr = NAME_IP_LIST[self.dropdown_menu.currentIndex()][1] self.server_thread = threading.Thread(target=self.server) self.server_running = True self.server_thread.start() self.time_is_up = False self.clock_seconds = 0 self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: yellow; color: red;}') def StdBtnClickedSlot(self): self.StandardButton.setStyleSheet("background-color: red") self.AdvancedButton.setStyleSheet("background-color: gray") self.level = 0 self.initialize() def AdvBtnClickedSlot(self): self.AdvancedButton.setStyleSheet("background-color: red") self.StandardButton.setStyleSheet("background-color: gray") self.level = 1 self.initialize() def randFieldConfig(self): #reset robot detection result self.detectedFieldConfig = 5 * np.ones((4, 16), dtype=np.int8) # standard # 0: empty, 12 # 1: single stressed, 8 # 2: single healthy, 44 # advanced # 0: empty, 12 # 1: single stressed, 8 # 2: single healthuy, 36 # 3: double, 4 # 4: tiller, 4 num_single_healthy_plants_per_row = 11 if self.level == 0 else 9 single_healthy_block = 2 * np.ones( (4, num_single_healthy_plants_per_row), dtype=np.int8) num_abnormal_spots = 20 if self.level == 0 else 28 abnormal_spots_array = np.zeros((1, num_abnormal_spots), dtype=np.int8) abnormal_spots_array[0, 12:20] = 1 if self.level == 1: abnormal_spots_array[0, 20:24] = 3 abnormal_spots_array[0, 24:28] = 4 shuffle_by_row = np.vectorize(np.random.permutation, signature='(n)->(n)') abnormal_spots_array = shuffle_by_row(abnormal_spots_array) abnormal_block = np.reshape(abnormal_spots_array, (4, -1)) fieldConfig = np.concatenate((single_healthy_block, abnormal_block), axis=1) fieldConfig = shuffle_by_row(fieldConfig) return fieldConfig
class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.filename = "" self.copiedItem = QByteArray() self.pasteOffset = 5 self.prevPoint = QPoint() self.addOffset = 5 self.borders = [] self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) self.view = GraphicsView() self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, PageSize[0], PageSize[1]) self.addBorders() self.view.setScene(self.scene) self.wrapped = [] # Needed to keep wrappers alive buttonLayout = QVBoxLayout() for text, slot in ( ("Add &Text", self.addText), ("Add &Box", self.addBox), ("Add Pi&xmap", self.addPixmap), ("&Align", None), ("&Copy", self.copy), ("C&ut", self.cut), ("&Paste", self.paste), ("&Delete...", self.delete), ("&Rotate", self.rotate), ("Pri&nt...", self.print_), ("&Open...", self.open), ("&Save", self.save), ("&Quit", self.accept)): button = QPushButton(text) if not MAC: button.setFocusPolicy(Qt.NoFocus) if slot is not None: button.clicked.connect(slot) if text == "&Align": menu = QMenu(self) for text, arg in ( ("Align &Left", Qt.AlignLeft), ("Align &Right", Qt.AlignRight), ("Align &Top", Qt.AlignTop), ("Align &Bottom", Qt.AlignBottom)): wrapper = functools.partial(self.setAlignment, arg) self.wrapped.append(wrapper) menu.addAction(text, wrapper) button.setMenu(menu) if text == "Pri&nt...": buttonLayout.addStretch(5) if text == "&Quit": buttonLayout.addStretch(1) buttonLayout.addWidget(button) buttonLayout.addStretch() layout = QHBoxLayout() layout.addWidget(self.view, 1) layout.addLayout(buttonLayout) self.setLayout(layout) fm = QFontMetrics(self.font()) self.resize(self.scene.width() + fm.width(" Delete... ") + 50, self.scene.height() + 50) self.setWindowTitle("Page Designer") def addBorders(self): self.borders = [] rect = QRectF(0, 0, PageSize[0], PageSize[1]) self.borders.append(self.scene.addRect(rect, Qt.yellow)) margin = 5.25 * PointSize self.borders.append(self.scene.addRect( rect.adjusted(margin, margin, -margin, -margin), Qt.yellow)) def removeBorders(self): while self.borders: item = self.borders.pop() self.scene.removeItem(item) del item def reject(self): self.accept() def accept(self): self.offerSave() QDialog.accept(self) def offerSave(self): if (Dirty and QMessageBox.question(self, "Page Designer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes): self.save() def position(self): point = self.mapFromGlobal(QCursor.pos()) if not self.view.geometry().contains(point): coord = random.randint(36, 144) point = QPoint(coord, coord) else: if point == self.prevPoint: point += QPoint(self.addOffset, self.addOffset) self.addOffset += 5 else: self.addOffset = 5 self.prevPoint = point return self.view.mapToScene(point) def addText(self): dialog = TextItemDlg(position=self.position(), scene=self.scene, parent=self) dialog.exec_() def addBox(self): BoxItem(self.position(), self.scene) def addPixmap(self): path = (QFileInfo(self.filename).path() if self.filename else ".") fname,filetype = QFileDialog.getOpenFileName(self, "Page Designer - Add Pixmap", path, "Pixmap Files (*.bmp *.jpg *.png *.xpm)") if not fname: return self.createPixmapItem(QPixmap(fname), self.position()) def createPixmapItem(self, pixmap, position, matrix=QTransform()): item = GraphicsPixmapItem(pixmap) item.setFlags(QGraphicsItem.ItemIsSelectable| QGraphicsItem.ItemIsMovable) item.setPos(position) item.setTransform(matrix) self.scene.clearSelection() self.scene.addItem(item) item.setSelected(True) global Dirty Dirty = True return item def selectedItem(self): items = self.scene.selectedItems() if len(items) == 1: return items[0] return None def copy(self): item = self.selectedItem() if item is None: return self.copiedItem.clear() self.pasteOffset = 5 stream = QDataStream(self.copiedItem, QIODevice.WriteOnly) self.writeItemToStream(stream, item) def cut(self): item = self.selectedItem() if item is None: return self.copy() self.scene.removeItem(item) del item def paste(self): if self.copiedItem.isEmpty(): return stream = QDataStream(self.copiedItem, QIODevice.ReadOnly) self.readItemFromStream(stream, self.pasteOffset) self.pasteOffset += 5 def setAlignment(self, alignment): # Items are returned in arbitrary order items = self.scene.selectedItems() if len(items) <= 1: return # Gather coordinate data leftXs, rightXs, topYs, bottomYs = [], [], [], [] for item in items: rect = item.sceneBoundingRect() leftXs.append(rect.x()) rightXs.append(rect.x() + rect.width()) topYs.append(rect.y()) bottomYs.append(rect.y() + rect.height()) # Perform alignment if alignment == Qt.AlignLeft: xAlignment = min(leftXs) for i, item in enumerate(items): item.moveBy(xAlignment - leftXs[i], 0) elif alignment == Qt.AlignRight: xAlignment = max(rightXs) for i, item in enumerate(items): item.moveBy(xAlignment - rightXs[i], 0) elif alignment == Qt.AlignTop: yAlignment = min(topYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - topYs[i]) elif alignment == Qt.AlignBottom: yAlignment = max(bottomYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - bottomYs[i]) global Dirty Dirty = True def rotate(self): for item in self.scene.selectedItems(): item.setRotation(item.rotation()+30) def delete(self): items = self.scene.selectedItems() if (len(items) and QMessageBox.question(self, "Page Designer - Delete", "Delete {0} item{1}?".format(len(items), "s" if len(items) != 1 else ""), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes): while items: item = items.pop() self.scene.removeItem(item) del item global Dirty Dirty = True def print_(self): dialog = QPrintDialog(self.printer) if dialog.exec_(): painter = QPainter(self.printer) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.TextAntialiasing) self.scene.clearSelection() self.removeBorders() self.scene.render(painter) self.addBorders() def open(self): self.offerSave() path = (QFileInfo(self.filename).path() if self.filename else ".") fname,filetype = QFileDialog.getOpenFileName(self, "Page Designer - Open", path, "Page Designer Files (*.pgd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.ReadOnly): raise IOError(str(fh.errorString())) items = self.scene.items() while items: item = items.pop() self.scene.removeItem(item) del item self.addBorders() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) magic = stream.readInt32() if magic != MagicNumber: raise IOError("not a valid .pgd file") fileVersion = stream.readInt16() if fileVersion != FileVersion: raise IOError("unrecognised .pgd file version") while not fh.atEnd(): self.readItemFromStream(stream) except IOError as e: QMessageBox.warning(self, "Page Designer -- Open Error", "Failed to open {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def save(self): if not self.filename: path = "." fname,filetype = QFileDialog.getSaveFileName(self, "Page Designer - Save As", path, "Page Designer Files (*.pgd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.WriteOnly): raise IOError(str(fh.errorString())) self.scene.clearSelection() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) stream.writeInt32(MagicNumber) stream.writeInt16(FileVersion) for item in self.scene.items(): self.writeItemToStream(stream, item) except IOError as e: QMessageBox.warning(self, "Page Designer -- Save Error", "Failed to save {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def readItemFromStream(self, stream, offset=0): type = "" position = QPointF() matrix = QTransform() rotateangle=0#add by yangrongdong type=stream.readQString() stream >> position >> matrix if offset: position += QPointF(offset, offset) if type == "Text": text = "" font = QFont() text=stream.readQString() stream >> font rotateangle=stream.readFloat() tx=TextItem(text, position, self.scene, font, matrix) tx.setRotation(rotateangle) elif type == "Box": rect = QRectF() stream >> rect style = Qt.PenStyle(stream.readInt16()) rotateangle=stream.readFloat() bx=BoxItem(position, self.scene, style, rect, matrix) bx.setRotation(rotateangle) elif type == "Pixmap": pixmap = QPixmap() stream >> pixmap rotateangle=stream.readFloat() px=self.createPixmapItem(pixmap, position, matrix) px.setRotation(rotateangle) def writeItemToStream(self, stream, item): if isinstance(item, TextItem): stream.writeQString("Text") stream<<item.pos()<< item.transform() stream.writeQString(item.toPlainText()) stream<< item.font() stream.writeFloat(item.rotation())#add by yangrongdong elif isinstance(item, GraphicsPixmapItem): stream.writeQString("Pixmap") stream << item.pos() << item.transform() << item.pixmap() stream.writeFloat(item.rotation())#add by yangrongdong elif isinstance(item, BoxItem): stream.writeQString("Box") stream<< item.pos() << item.transform() << item.rect stream.writeInt16(item.style) stream.writeFloat(item.rotation())#add by yangrongdong
class Board(QGraphicsView): def __init__(self, score, player_clock, ai_clock, add_comment, text_field, set_prompt, confirm_button, disable_buttons, sack_counter): QGraphicsView.__init__(self) self.scale = 1 self._board_squares = {} self._other_squares = {} self._bonus_fields = [] self._labels = {} self.scene = QGraphicsScene() self.build_board_scene() self.prepare_board() self.setScene(self.scene) self.player_clock = player_clock self.ai_clock = ai_clock self.add_info = add_comment self.set_prompt = set_prompt self.disable_buttons = disable_buttons self.confirm_button = confirm_button self.text_field = text_field self.is_game_started = False # parameters visible for AI self.tiles_for_ai = {} # sack represents sack self.sack = None self.sack_counter = sack_counter # score represents total score of both players self.score = score # tiles represent all tiles on board self._tiles = {} # latest tiles represent tiles added in last turn self.new_tiles = [] self._latest_tiles = set() self._tiles_in_rack = set() self._tiles_to_exchange = set() self._blanks = [] self._points = 0 self._words = [] self._is_connected = False self.ai = None def auto_resize(self): if self.height() / self.width() < DEFAULT_HEIGHT / DEFAULT_WIDTH: scale = round(self.height() / DEFAULT_HEIGHT, 1) else: scale = round(self.width() / DEFAULT_WIDTH, 1) if abs(scale - self.scale) < 0.0001: return self.scale = scale self.scene.setSceneRect(-SQUARE_SIZE / 2, -SQUARE_SIZE / 2, SQUARE_SIZE * 16 * self.scale, SQUARE_SIZE * 19 * self.scale) for tile in self._tiles.values(): tile.resize(self.scale) for square in self._board_squares.values(): square.setScale(self.scale) for square in self._other_squares.values(): square.setScale(self.scale) for x, y in self._labels: label = self._labels.get((x, y)) label.setScale(self.scale) label.setPos(x * self.scale, y * self.scale) def prepare_game(self): self.sack = Sack(self.sack_counter) self.ai = AI(self.tiles_for_ai, self.sack) def reset_game(self): self.is_game_started = False self.ai.stop() for tile in self._tiles.values(): self.scene.removeItem(tile) self.tiles_for_ai.clear() self._tiles.clear() self._latest_tiles.clear() self._tiles_in_rack.clear() self._tiles_to_exchange.clear() self._blanks.clear() self._words.clear() self._points = 0 self._is_connected = False self.prepare_game() def start_game(self): if self.is_game_started: self.reset_game() self.prepare_game() self.is_game_started = True self.ai.is_turn = bool(getrandbits(1)) self.add_letters_to_rack() self.ai.finished.connect(self.end_ai_turn) self.ai.start() if self.ai.is_turn: self.add_info('Przeciwnik zaczyna') self.start_ai_turn() else: self.add_info('Zaczynasz') self.player_clock.start() def move_to_rack(self, tile): old_coords = tile.coords if old_coords in self._tiles_in_rack: return coords = Coords(LEFT_RACK_BOUND, RACK_ROW) while coords in self._tiles_in_rack: coords = coords.move(RIGHT) if old_coords in self._tiles_to_exchange: self._tiles_to_exchange.remove(old_coords) else: self._latest_tiles.remove(old_coords) del self._tiles[old_coords] self._tiles[coords] = tile self._tiles_in_rack.add(coords) tile.move_to_coords(coords) def collect_tiles(self): for coords in set.union(self._latest_tiles, self._tiles_to_exchange): tile = self.get_tile(coords) self.move_to_rack(tile) def skip_turn(self): self.collect_tiles() self.score.add_points('Gracz', '(Pominięcie ruchu)', 0) self.start_ai_turn() def player_ends(self): self.player_clock.stop() points = 0 letters = ' ' for letter in self.ai.rack: points += Sack.get_value(letter) letters += f'{letter}, ' self.score.add_points('AI', f'(Zostały {letters[:-2]})', -points) self.score.add_points('Gracz', '', points) self.end_game() def ai_ends(self): points = 0 letters = ' ' for coords in self._tiles_in_rack: tile = self.get_tile(coords) points += tile.points letters += f'{tile.letter}, ' for coords in self._tiles_to_exchange: tile = self.get_tile(coords) points += tile.points letters += f'{tile.letter}, ' self.score.add_points('Gracz', f'(Zostały {letters[:-2]})', -points) self.score.add_points('AI', '', points) self.end_game() def end_game(self): self.disable_buttons(True) player_score = self.score.get_score('Gracz') ai_score = self.score.get_score('AI') if player_score > ai_score: self.add_info('Gratulacje! Udało Ci się pokonać algorytm!') elif player_score < ai_score: self.add_info('Tym razem się nie udało. Próbuj dalej :)') else: self.add_info('Dobry remis nie jest zły ;)') def add_letters_to_rack(self, letters=None): if not letters: letters = self.sack.draw(MAX_RACK_SIZE - len(self._tiles_in_rack) - len(self._tiles_to_exchange)) for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1): if not letters: return coords = Coords(column, RACK_ROW) if not self.get_tile(coords) and len(self._tiles_in_rack) + len(self._tiles_to_exchange) < MAX_RACK_SIZE: letter = letters.pop() coords = Coords(column, RACK_ROW) points = Sack.get_value(letter) tile = Tile(letter, points, coords, self.scale, self.on_tile_move, self.move_to_rack) self.scene.addItem(tile) self._tiles_in_rack.add(coords) self._tiles[coords] = tile def exchange_letters(self): if self.ai.is_turn: self.add_info('Ruch przeciwnika') return if not self._tiles_to_exchange: self.add_info('Brak liter do wymiany') return letters_to_exchange = [] for coords in self._tiles_to_exchange: tile = self.get_tile(coords) letters_to_exchange.append(tile.letter) del self._tiles[tile.coords] self.scene.removeItem(tile) letters_on_board = [] for coords in self._latest_tiles: tile = self.get_tile(coords) letters_on_board.append(tile.letter) del self._tiles[tile.coords] self.scene.removeItem(tile) self._tiles_to_exchange.clear() self._latest_tiles.clear() new_letters = self.sack.exchange(letters_to_exchange) self.score.add_points('Gracz', '(wymiana liter)', 0) if not new_letters: self.add_info('Za mało płytek w worku') self.add_letters_to_rack(letters_to_exchange + letters_on_board) return self.add_info('Wymieniłeś/aś litery') self.add_letters_to_rack(new_letters + letters_on_board) self.start_ai_turn() def start_ai_turn(self): self.player_clock.stop() self.tiles_for_ai.clear() for coords in self._latest_tiles: self.tiles_for_ai[coords] = self.get_tile(coords) for tile in self.new_tiles: tile.remove_highlight() self.new_tiles.clear() self.ai.is_turn = True self.ai_clock.start() self.disable_buttons(True) def end_ai_turn(self): if not self.is_game_started: return self.ai_clock.stop() self.disable_buttons(False) word = self.ai.word words = [word] for coords in self._latest_tiles: tile = self.get_tile(coords) tile.remove_highlight() self._latest_tiles.clear() if word: for coords in word.added_letters: letter, points = word.added_letters.get(coords) tile = Tile(letter, points, coords, self.scale) tile.place() self._tiles[coords] = tile self.scene.addItem(tile) self.new_tiles.append(tile) perpendicular_word = self.find_word(coords, ~word.direction(), False) if perpendicular_word: words.append(perpendicular_word) self.score.add_points('AI', words, word.sum_up()) else: self.add_info(f'Komputer wymienił litery') self.score.add_points('AI', '(wymiana liter)', 0) if not self.ai.rack: self.ai_ends() return self.player_clock.start() def wait_for_blank(self, blank): self._blanks.append(blank) self.set_prompt("Jaką literą ma być blank?") self.text_field.setDisabled(False) self.confirm_button.setDisabled(False) self.disable_buttons(True) def stop_waiting_for_blank(self): self.set_prompt('') self.text_field.setDisabled(True) self.text_field.clear() self.confirm_button.setDisabled(True) self.disable_buttons(False) def revert_blanks(self): for blank in self._blanks: blank.change_back() self._blanks.clear() self.stop_waiting_for_blank() def blank_entered(self): tile = self._blanks[-1] new_letter = self.text_field.text() if new_letter.lower() in Sack.values_without_blank(): tile.change_to_blank(new_letter) self.stop_waiting_for_blank() self.end_turn() else: self.add_info('Podaj poprawną literę') self.text_field.clear() return def end_turn(self): if self.ai.is_turn: self.add_info('Ruch przeciwnika') return self._is_connected = False if not self._latest_tiles: self.add_info('Musisz najpierw wykonać ruch') return if not self.get_tile(Coords.central()): self.add_info('Pierwszy wyraz musi przechodzić przez środek') return if Coords.central() in self._latest_tiles: self._is_connected = True if len(self._latest_tiles) == 1: self.add_info('Wyraz musi zawierać przynajmniej dwie litery') return first_tile_coords = min(self._latest_tiles) last_tile_coords = max(self._latest_tiles) if first_tile_coords.is_same_column(last_tile_coords): direction = DOWN else: direction = RIGHT if len(self._latest_tiles) == 1 and (self.get_tile(first_tile_coords.move(RIGHT)) or self.get_tile( first_tile_coords.move(RIGHT))): self._is_connected = True columns = set() rows = set() for tile in self._latest_tiles: columns.add(tile.x) rows.add(tile.y) if len(rows) > 1 and len(columns) > 1: self.add_info('Litery muszą być ułożone w jednej linii') return while self.get_tile(first_tile_coords.move(-direction)): first_tile_coords = first_tile_coords.move(-direction) while self.get_tile(last_tile_coords.move(direction)): last_tile_coords = last_tile_coords.move(direction) current_coords = first_tile_coords while current_coords <= last_tile_coords: tile = self.get_tile(current_coords) if not tile: self.add_info("Litery muszą należeć do tego samego wyrazu") return if tile.is_placed or self.get_tile( current_coords.move(~direction)) or self.get_tile( current_coords.move(-~direction)): self._is_connected = True if tile.letter == BLANK: self.wait_for_blank(tile) return current_coords = current_coords.move(direction) if not self._is_connected: self.add_info('Wyraz musi się stykać z występującymi już na planszy') return self._words.clear() self._points = 0 self.find_word(first_tile_coords, direction) if len(columns) > 1: for column in columns: self.find_word(Coords(column, first_tile_coords.y), ~direction) else: for row in rows: self.find_word(Coords(first_tile_coords.x, row), ~direction) for word in self._words: if not Dictionary.is_word_in_dictionary(word): self.add_info(f'słowo "{word}" nie występuje w słowniku') if self._blanks: self.revert_blanks() return for coords in self._latest_tiles: tile = self.get_tile(coords) tile.place() self._blanks.clear() if len(self._latest_tiles) == MAX_RACK_SIZE: self._points += 50 self.score.add_points('Gracz', self._words, self._points) self.add_letters_to_rack() if not self._tiles_in_rack and not self._tiles_to_exchange and not self.sack.how_many_remain(): self.player_ends() return self.start_ai_turn() def find_word(self, coords, direction, is_players_turn=True): word = '' word_points = 0 word_multiplier = 1 direction = abs(direction) first_tile = coords while self.get_tile(first_tile.move(-direction)): first_tile = first_tile.move(-direction) last_tile = coords while self.get_tile(last_tile.move(direction)): last_tile = last_tile.move(direction) if first_tile == last_tile: return current_tile = first_tile while current_tile <= last_tile: tile = self.get_tile(current_tile) points = tile.points if not tile.is_placed: if current_tile in double_letter_bonuses: points *= 2 elif current_tile in triple_letter_bonuses: points *= 3 elif current_tile in double_word_bonuses: word_multiplier *= 2 elif current_tile in triple_word_bonuses: word_multiplier *= 3 word_points += points word += tile.letter current_tile = current_tile.move(direction) if is_players_turn: self._words.append(word) self._points += word_points * word_multiplier else: return word def swap_tiles(self, tile, other_tile): tile.swap_with_other(other_tile) self._tiles[tile.coords] = tile self._tiles[other_tile.coords] = other_tile def on_tile_move(self, tile): if not tile.coords.is_valid(): tile.undo_move() return if tile.coords.is_on_board() and self.ai.is_turn: self.add_info('Ruch przeciwnika') tile.undo_move() return other_tile = None if tile.coords in set.union(self._latest_tiles, self._tiles_in_rack, self._tiles_to_exchange): other_tile = self.get_tile(tile.coords) if other_tile: self.swap_tiles(tile, other_tile) elif self.get_tile(tile.coords): tile.undo_move() return else: del self._tiles[tile.old_coords] if tile.old_coords.is_in_rack(): self._tiles_in_rack.remove(tile.old_coords) elif tile.old_coords.is_in_exchange_zone(): self._tiles_to_exchange.remove(tile.old_coords) else: self._latest_tiles.remove(tile.old_coords) self._tiles[tile.coords] = tile if tile.coords.is_in_rack(): self._tiles_in_rack.add(tile.coords) elif tile.coords.is_in_exchange_zone(): self._tiles_to_exchange.add(tile.coords) else: self._latest_tiles.add(tile.coords) def get_tile(self, coords: Coords) -> Tile: return self._tiles.get(coords) def build_board_scene(self): self.build_squares() self.prepare_bonus_fields() self.build_bonus_fields() self.build_rack() self.build_exchange_zone() self.build_labels() def build_squares(self): brush = QBrush(LIGHT_SEA_GREEN) pen = QPen(DARK_SEA_GREEN, 1, Qt.SolidLine) for row in range(LAST_ROW + 1): for column in range(LAST_COLUMN + 1): square = self.add_square(row, column, pen, brush) self._board_squares[Coords(row, column)] = square def build_bonus_fields(self): for bonus_field in self._bonus_fields: brush = bonus_field["Brush"] pen = bonus_field["Pen"] bonus_fields = [] for coords in bonus_field["Coords"]: label = bonus_field["Name"] if coords == Coords.central(): label = '✸' square = self._board_squares[coords] square.setZValue(2) bonus_fields.append(square) field_name = QGraphicsSimpleTextItem(label) font = field_name.font() font.setPointSize(10) if coords == Coords.central(): font.setPointSize(20) fm = QFontMetrics(font) field_name.setZValue(2.1) field_name.setFont(font) x = coords.x * SQUARE_SIZE + (SQUARE_SIZE - fm.width(label)) / 2 y = coords.y * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2 field_name.setPos(x, y) field_name.setBrush(bonus_field["Label brush"]) self._labels[(x, y)] = field_name self.scene.addItem(field_name) paint_graphic_items(bonus_fields, pen, brush) def build_rack(self): brush = QBrush(LIGHT_BROWN) pen = QPen(BROWN, 1, Qt.SolidLine) for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1): square = self.add_square(RACK_ROW, column, pen, brush) self._other_squares[Coords(column, RACK_ROW)] = square def build_exchange_zone(self): brush = QBrush(LIGHT_BROWN) pen = QPen(BROWN, 1, Qt.SolidLine) for column in range(LEFT_RACK_BOUND, RIGHT_RACK_BOUND + 1): square = self.add_square(EXCHANGE_ROW, column, pen, brush) self._other_squares[Coords(column, EXCHANGE_ROW)] = square text = 'Litery do wymiany → ' font = QFont('Verdana', 10) fm = QFontMetrics(font) x = SQUARE_SIZE * LEFT_RACK_BOUND - fm.width(text) y = SQUARE_SIZE * EXCHANGE_ROW + (SQUARE_SIZE - fm.height()) / 2 label = QGraphicsSimpleTextItem(text) label.setPos(x, y) label.setFont(font) label.setBrush(QBrush(Qt.white)) self._labels[(x, y)] = label self.scene.addItem(label) def add_square(self, row, column, pen, brush): height = SQUARE_SIZE width = SQUARE_SIZE column_distance = column * width row_distance = row * height x = column_distance y = row_distance rectangle = QRectF(x, y, width, height) return self.scene.addRect(rectangle, pen, brush) def build_labels(self): font = QFont('Verdana', 10) fm = QFontMetrics(font) for count in range(LAST_ROW + 1): number = str(count + 1) number_label = QGraphicsSimpleTextItem(number) x = -fm.width(number) - SQUARE_SIZE / 8 y = count * SQUARE_SIZE + (SQUARE_SIZE - fm.height()) / 2 number_label.setPos(x, y) number_label.setFont(font) number_label.setBrush(QBrush(Qt.white)) self._labels[(x, y)] = number_label letter = chr(count + ord('A')) letter_label = QGraphicsSimpleTextItem(letter) x = count * SQUARE_SIZE + (SQUARE_SIZE - fm.width(letter)) / 2 y = -fm.height() - SQUARE_SIZE / 8 letter_label.setPos(x, y) letter_label.setFont(font) letter_label.setBrush(QBrush(Qt.white)) self._labels[(x, y)] = letter_label self.scene.addItem(number_label) self.scene.addItem(letter_label) def prepare_bonus_fields(self): triple_word_bonus_fields = { "Name": "3S", "Pen": QPen(DARK_RED, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin), "Brush": QBrush(RED), "Label brush": QBrush(DARK_RED), "Coords": triple_word_bonuses } self._bonus_fields.append(triple_word_bonus_fields) double_word_bonus_fields = { "Name": "2S", "Pen": QPen(RED, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin), "Brush": QBrush(PINK), "Label brush": QBrush(RED), "Coords": double_word_bonuses } self._bonus_fields.append(double_word_bonus_fields) triple_letter_bonus_fields = { "Name": "3L", "Pen": QPen(NAVY_BLUE, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin), "Brush": QBrush(BLUE), "Label brush": QBrush(NAVY_BLUE), "Coords": triple_letter_bonuses } self._bonus_fields.append(triple_letter_bonus_fields) double_letter_bonus_fields = { "Name": "2L", "Pen": QPen(BLUE2, 1, Qt.SolidLine, Qt.RoundCap, Qt.BevelJoin), "Brush": QBrush(LIGHT_BLUE), "Label brush": QBrush(BLUE2), "Coords": double_letter_bonuses } self._bonus_fields.append(double_letter_bonus_fields) def prepare_board(self): self.scene.setSceneRect(-SQUARE_SIZE / 2, -SQUARE_SIZE / 2, SQUARE_SIZE * 16, SQUARE_SIZE * 19) self.scene.setBackgroundBrush(QBrush(SEA_GREEN)) self.setMinimumSize(MINIMAL_WIDTH, MINIMAL_HEIGHT) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
class MainApp(QMainWindow, Ui_MainWindow): process_Num = 0 segments_list = [] def __init__(self, parent=None): super(MainApp, self).__init__(parent) QMainWindow.__init__(self) self.setupUi(self) self.processes_list = [] self.memory_created = 0 # use this variable as a flag self.process_name = "" self.scene = QGraphicsScene() self.red = QColor(qRgb(172, 50, 99)) self.blue = QColor(qRgb(50, 150, 203)) self.memory_width = 150 self.memory_height = 600 self.view.setScene(self.scene) self.setup_Ui() self.init_Buttons() def setup_Ui(self): """ UI setup goes here """ self.center_window() self.setWindowTitle("Memory Management") self.setFixedSize(530, 750) self.NumSegments.setMinimum(0) self.NumSegments.setMaximum(999) def center_window(self): # centering window qtRectangle = self.frameGeometry() centerPoint = QDesktopWidget().availableGeometry().center() qtRectangle.moveCenter(centerPoint) self.move(qtRectangle.topLeft()) def init_Buttons(self): """ Buttons initializations and slots connections goes here """ self.EnterSegments.clicked.connect(self.goToSegmentsWindow) self.SizeEnter.clicked.connect(self.createMemory) self.AddHole_button.clicked.connect(self.add_hole) self.deallocate_button.clicked.connect(self.deallocate_process) self.allocate_button.clicked.connect(self.allocate_memory) self.compact_button.clicked.connect(self.compact_memory) self.clear_button.clicked.connect(self.clear_memory) def DrawMemory(self): iterator = 0 self.scene.clear() for element in self.memory.get_memoryContents(): self.scene.addRect( 0, # x (iterator / self.memory.get_memorySize()) * self.memory_height, # y self.memory_width, # w (element[2] / self.memory.get_memorySize()) * self.memory_height, # h self.red, hex_to_qcolor(self.memory.color_from_name(element[1])), ) self.scene.addText(element[0]).setPos( 0, (iterator / self.memory.get_memorySize()) * self.memory_height ) self.scene.addText(str(iterator)).setPos( self.memory_width, (iterator / self.memory.get_memorySize()) * self.memory_height ) iterator = iterator + element[2] def createMemory(self): try: memory_size = int(self.MemorySize.text()) if memory_size > 0: self.memory = Memory(memory_size) self.memory_created = 1 self.DrawMemory() else: self.show_msgBox( "Memory Size error!\nSet Memory Size please!" ) # create error msg here except: self.show_msgBox( "Memory Size error!\nMemory Size Text Box accepts numeric values only." ) # create error msg to write only number here def add_hole(self): if self.memory_created: try: hole_address = int(self.HoleAddress.text()) hole_size = int(self.HoleSize.text()) if hole_size > 0: self.memory.add_hole(hole_address, hole_size) self.memory.Merge() self.DrawMemory() else: self.show_msgBox( "Hole Size Value Error!\nHole cannot be of size 0" ) # error msg here, plz add a proper hole size except ValueError: self.show_msgBox("Please Make sure you entered numeric values.") except AssertionError as error: if ( str(error) == "Can't add a hole here! There's already a hole located in this address" ): self.show_msgBox(str(error)) else: self.show_msgBox( "Memory Limit Exceeded!\n" + str(error) ) # error msg here, hole size or base address are beyond memory size else: self.show_msgBox( "No Memory Found.\nPlease Create Memory before creating a hole!" ) # error msg here, plz create a memory by assigning its size above def allocate_memory(self): try: if self.memory_created: algorithm = self.algorithms_list.currentText() if len(self.process_name) > 0 and not ( self.memory.color_from_name(self.process_name) in chain(*self.memory.get_memoryContents()) ): if algorithm == "First Fit": self.memory.first_fit(self.segments_list, self.process_name) self.DrawMemory() self.NumSegments.setValue(0) elif algorithm == "Best Fit": self.memory.best_fit(self.segments_list, self.process_name) self.DrawMemory() self.NumSegments.setValue(0) else: self.memory.worst_fit(self.segments_list, self.process_name) self.DrawMemory() self.NumSegments.setValue(0) else: self.show_msgBox( "No Selected Process!\nAdd Segments First to be able to allocate a process" ) # error msg here else: self.show_msgBox( "No Memory Found.\nPlease Create Memory before allocate processes!" ) # error msg here, plz create a memory by assigning its size above except AssertionError as error: self.show_msgBox("Memory Limit Exceeded!\n" + str(error)) def deallocate_process(self): process = self.processesBox.currentText() if self.memory_created: if len(process) > 0: self.memory.deallocate(process) process_index = self.processesBox.currentIndex() self.processesBox.removeItem(process_index) self.memory.Merge() self.DrawMemory() else: self.show_msgBox( "No Process Found.\nPlease Add process first!" ) # msg error here, create memory first else: self.show_msgBox( "No Memory Found.\nPlease Create Memory first!" ) # msg error here, create memory first def goToSegmentsWindow(self): if self.memory_created: segmentsNo = self.NumSegments.value() if segmentsNo > 0: self.segments_window = SegmentWindow() self.segments_window.set_segmentsNo(segmentsNo) self.segments_window.show() self.segments_window.set_processesNum(self.process_Num + 1) self.segments_window.segmentsData_passingSig.connect( self.receive_segmentsData ) else: self.show_msgBox( "Input Value Error\nNumber of segments must be more than 0" ) # error handling else: self.show_msgBox( "No Memory Found.\nPlease Create Memory first!" ) # error handling def receive_segmentsData(self, segList): print(segList) # print for checking self.segments_list = segList self.process_Num += 1 self.segments_window.close() self.processes_list.append("P" + str(self.process_Num)) self.processesBox.addItem("P" + str(self.process_Num)) self.process_name = "P" + str(self.process_Num) def compact_memory(self): if self.memory_created: self.memory.compact() self.memory.Merge() self.DrawMemory() else: self.show_msgBox("No Memory Found.\nPlease Create Memory first!") def clear_memory(self): if self.memory_created: del self.memory # deleting memory object self.memory_created = 0 # set memory existence flag = 0 self.clear_fields() # code to delete or remove memory contents in graphics should be added here else: self.show_msgBox("No Memory Found.\nPlease Create Memory first!") def clear_fields(self): self.MemorySize.setText("0") self.HoleAddress.setText("0") self.HoleSize.setText("0") self.NumSegments.setValue(0) processesNumber = int(self.processesBox.count()) # print(processesNumber) if processesNumber > 0: for i in range(processesNumber): process = self.processesBox.currentText() if len(process) > 0: process_index = self.processesBox.currentIndex() self.processesBox.removeItem(process_index) self.process_Num = 0 self.process_name = "" self.processes_list = [] self.segments_list = [] self.scene.clear() def show_msgBox(self, msg): self.msgBox = QMessageBox() self.msgBox.setWindowTitle("Error!") self.msgBox.setIcon(QMessageBox.Warning) self.msgBox.setText(msg) self.msgBox.setStandardButtons(QMessageBox.Ok) self.msgBox.exec_()
class AMANDisplay(QGraphicsView): def __init__(self): super(AMANDisplay, self).__init__() self.setGeometry(0, 0, 500, 600) self.setStyleSheet("background-color:#233370") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, 500, 600) # Timeline boundaries pen = QPen(QColor("white")) brush = QBrush(QColor("#233370")) self.scene.addLine(220, 0, 220, 600, pen) self.scene.addLine(280, 0, 280, 600, pen) self.scene.addLine(0, 30, 500, 30, pen) timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush) timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True) # Timeline scale self.timeline = QGraphicsItemGroup() self.timeline.setParentItem(timelinebox) self.timeticks = [] for i in range(40): y = 15 * i w = 6 if i % 5 == 0: w = 10 self.timeticks.append(self.scene.addText("%02d" % (40 - i), QFont("Courier", 10))) self.timeticks[-1].setPos(240, y - 10) self.timeticks[-1].setDefaultTextColor(QColor("white")) self.timeline.addToGroup(self.timeticks[-1]) self.timeline.addToGroup(self.scene.addLine(220, y, 220 + w, y, pen)) self.timeline.addToGroup(self.scene.addLine(280 - w, y, 280, y, pen)) self.lrwy = self.scene.addText("18R", QFont("Arial", 20, 50)) self.lrwy.setPos(1, 1) self.lrwy.setDefaultTextColor(QColor("white")) # Finalize self.setScene(self.scene) self.show() def update(self, simt, data): # data has: ids, iafs, eats, etas, delays, rwys, spdratios # First delete old labels for (key,) in self.aircraft.keys: if key not in data.ids: # del label del self.aircraft[key] for i in len(data.ids): if data.ids[i] not in self.aircraft: # self.aircraft[data.ids[i]] = QLabel() pass # Generate the new label text and position newtext = "<font color=Red>bla</font>" # veranderen lbl = self.aircraft[data.ids[i]] lbl.setText(newtext) lbl.move(posx, posy) # move in pixels
class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1100, 700) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) MainWindow.setStyleSheet("color: rgb(85, 85, 255);\n" "font: 25 10pt \"Calibri Light\";") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout_2.setObjectName("gridLayout_2") self.table = QtWidgets.QTableWidget(self.centralwidget) self.table.setObjectName("table") self.table.setColumnCount(5) self.table.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.table.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() self.table.setHorizontalHeaderItem(1, item) item = QtWidgets.QTableWidgetItem() self.table.setHorizontalHeaderItem(2, item) item = QtWidgets.QTableWidgetItem() self.table.setHorizontalHeaderItem(3, item) item = QtWidgets.QTableWidgetItem() self.table.setHorizontalHeaderItem(4, item) self.gridLayout_2.addWidget(self.table, 7, 0, 1, 1) self.label_gantt_chart = QtWidgets.QLabel(self.centralwidget) self.label_gantt_chart.setStyleSheet("font: 75 12pt \"Calibri\";\n" "color: rgb(0, 85, 127);") self.label_gantt_chart.setObjectName("label_gantt_chart") self.gridLayout_2.addWidget(self.label_gantt_chart, 11, 0, 1, 2, QtCore.Qt.AlignHCenter) self.label_processes_data = QtWidgets.QLabel(self.centralwidget) self.label_processes_data.setStyleSheet("font: 75 12pt \"Calibri\";\n" "color: rgb(0, 85, 127);") self.label_processes_data.setObjectName("label_processes_data") self.gridLayout_2.addWidget(self.label_processes_data, 2, 0, 1, 1, QtCore.Qt.AlignHCenter) self.chart_view = QtWidgets.QGraphicsView(self.centralwidget) self.chart_view.setObjectName("chart_view") self.gridLayout_2.addWidget(self.chart_view, 15, 0, 1, 2) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_2.addItem(spacerItem, 1, 0, 1, 2) self.formLayout = QtWidgets.QFormLayout() self.formLayout.setObjectName("formLayout") self.label_avg_waiting_time = QtWidgets.QLabel(self.centralwidget) self.label_avg_waiting_time.setObjectName("label_avg_waiting_time") self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_avg_waiting_time) self.label_avg_turnaround_time = QtWidgets.QLabel(self.centralwidget) self.label_avg_turnaround_time.setObjectName( "label_avg_turnaround_time") self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_avg_turnaround_time) self.avg_waiting_label = QtWidgets.QLabel(self.centralwidget) self.avg_waiting_label.setText("") self.avg_waiting_label.setObjectName("avg_waiting_label") self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.avg_waiting_label) self.avg_turnaround_label = QtWidgets.QLabel(self.centralwidget) self.avg_turnaround_label.setText("") self.avg_turnaround_label.setObjectName("avg_turnaround_label") self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.avg_turnaround_label) self.gridLayout_2.addLayout(self.formLayout, 6, 1, 1, 1) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.label_desired_algorithm = QtWidgets.QLabel(self.centralwidget) self.label_desired_algorithm.setObjectName("label_desired_algorithm") self.horizontalLayout_2.addWidget(self.label_desired_algorithm, 0, QtCore.Qt.AlignRight) self.algorithm_dropdown = QtWidgets.QComboBox(self.centralwidget) self.algorithm_dropdown.setStyleSheet( "background-color: rgb(247, 248, 255);") self.algorithm_dropdown.setObjectName("algorithm_dropdown") self.algorithm_dropdown.addItem("") self.algorithm_dropdown.setItemText(0, "") self.algorithm_dropdown.addItem("") self.algorithm_dropdown.addItem("") self.algorithm_dropdown.addItem("") self.algorithm_dropdown.addItem("") self.algorithm_dropdown.addItem("") self.algorithm_dropdown.addItem("") self.horizontalLayout_2.addWidget(self.algorithm_dropdown) self.label_time_quantum = QtWidgets.QLabel(self.centralwidget) self.label_time_quantum.setObjectName("label_time_quantum") self.horizontalLayout_2.addWidget(self.label_time_quantum, 0, QtCore.Qt.AlignRight) self.tq_in = QtWidgets.QLineEdit(self.centralwidget) self.tq_in.setObjectName("tq_in") self.horizontalLayout_2.addWidget(self.tq_in, 0, QtCore.Qt.AlignLeft) self.simulate_b = QtWidgets.QPushButton(self.centralwidget) self.simulate_b.setStyleSheet("background-color: rgb(247, 248, 255);") self.simulate_b.setObjectName("simulate_b") self.horizontalLayout_2.addWidget(self.simulate_b) self.clear_b = QtWidgets.QPushButton(self.centralwidget) self.clear_b.setStyleSheet("background-color: rgb(247, 248, 255);") self.clear_b.setObjectName("clear_b") self.horizontalLayout_2.addWidget(self.clear_b) self.gridLayout_2.addLayout(self.horizontalLayout_2, 13, 0, 2, 2) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_2.addItem(spacerItem1, 8, 0, 1, 2) self.label_scheduling_stats = QtWidgets.QLabel(self.centralwidget) self.label_scheduling_stats.setStyleSheet( "font: 75 12pt \"Calibri\";\n" "color: rgb(0, 85, 127);") self.label_scheduling_stats.setObjectName("label_scheduling_stats") self.gridLayout_2.addWidget(self.label_scheduling_stats, 2, 1, 1, 1, QtCore.Qt.AlignHCenter) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.add_b = QtWidgets.QPushButton(self.centralwidget) self.add_b.setStyleSheet("background-color: rgb(247, 248, 255);") self.add_b.setObjectName("add_b") self.horizontalLayout_3.addWidget(self.add_b) self.remove_b = QtWidgets.QPushButton(self.centralwidget) self.remove_b.setStyleSheet("background-color: rgb(247, 248, 255);") self.remove_b.setObjectName("remove_b") self.horizontalLayout_3.addWidget(self.remove_b) self.gridLayout_2.addLayout(self.horizontalLayout_3, 6, 0, 1, 1) self.stats_table = QtWidgets.QTableWidget(self.centralwidget) self.stats_table.setObjectName("stats_table") self.stats_table.setColumnCount(4) self.stats_table.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.stats_table.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() self.stats_table.setHorizontalHeaderItem(1, item) item = QtWidgets.QTableWidgetItem() self.stats_table.setHorizontalHeaderItem(2, item) item = QtWidgets.QTableWidgetItem() self.stats_table.setHorizontalHeaderItem(3, item) self.gridLayout_2.addWidget(self.stats_table, 7, 1, 1, 1) self.title_label = QtWidgets.QLabel(self.centralwidget) self.title_label.setStyleSheet("font: 75 16pt \"Calibri\";\n" "text-decoration: underline;\n" "color: rgb(0, 85, 127);") self.title_label.setObjectName("title_label") self.gridLayout_2.addWidget(self.title_label, 0, 0, 1, 2, QtCore.Qt.AlignHCenter) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_2.addItem(spacerItem2, 12, 0, 1, 2) spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_2.addItem(spacerItem3, 3, 0, 1, 2) MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) # Attributes self.row = 0 self.processes_list = [] self.chart = [] self.clear_flag = False self.comboBox = [] self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # Buttons Connections self.add_b.clicked.connect(lambda: self.add_clicked()) self.remove_b.clicked.connect(lambda: self.remove_clicked()) self.simulate_b.clicked.connect(lambda: self.simulate_clicked()) self.clear_b.clicked.connect(lambda: self.clear_clicked()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) item = self.table.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "PID")) item = self.table.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "Color")) item = self.table.horizontalHeaderItem(2) item.setText(_translate("MainWindow", "Arrival Time")) item = self.table.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Burst Time")) item = self.table.horizontalHeaderItem(4) item.setText(_translate("MainWindow", "Priority")) self.label_gantt_chart.setText(_translate("MainWindow", "GANTT Chart")) self.label_processes_data.setText( _translate("MainWindow", "Processes Data")) self.label_avg_waiting_time.setText( _translate("MainWindow", "Average Waiting Time:")) self.label_avg_turnaround_time.setText( _translate("MainWindow", "Average Turnaround Time:")) self.label_desired_algorithm.setText( _translate("MainWindow", "Desired Scheduling Algorithm")) self.algorithm_dropdown.setItemText( 1, _translate("MainWindow", "First Come, First Served")) self.algorithm_dropdown.setItemText( 2, _translate( "MainWindow", "Shortest Job First (Non Preemptive)")) self.algorithm_dropdown.setItemText( 3, _translate("MainWindow", "Shortest Job First (Preemptive)")) self.algorithm_dropdown.setItemText( 4, _translate( "MainWindow", "Priority (Non Preemptive)" )) self.algorithm_dropdown.setItemText( 5, _translate( "MainWindow", "Priority (Preemptive)")) self.algorithm_dropdown.setItemText( 6, _translate("MainWindow", "Round Robin")) self.label_time_quantum.setText( _translate("MainWindow", "RR Time Quantum")) self.simulate_b.setStatusTip( _translate("MainWindow", "Simulates CPU Scheduling and View GANTT Chart")) self.simulate_b.setText(_translate("MainWindow", "Simulate")) self.clear_b.setStatusTip( _translate("MainWindow", "Clears Application")) self.clear_b.setText(_translate("MainWindow", "Clear")) self.label_scheduling_stats.setText( _translate("MainWindow", "Scheduling Statistics")) self.add_b.setStatusTip( _translate("MainWindow", "Adds a Process Entry to the Table")) self.add_b.setText(_translate("MainWindow", "Add Process")) self.remove_b.setStatusTip( _translate("MainWindow", "Removes a Process Entry from the Table")) self.remove_b.setText(_translate("MainWindow", "Remove Process")) item = self.stats_table.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "PID")) item = self.stats_table.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "Finish Time")) item = self.stats_table.horizontalHeaderItem(2) item.setText(_translate("MainWindow", "Turnaround Time")) item = self.stats_table.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Waiting Time")) self.title_label.setText(_translate("MainWindow", "CPU Scheduler")) # UI Functionality def get_departure_time(self, pid): for index in range(len(self.chart) - 1, -1, -1): if self.chart[index] == "Idle": continue elif self.chart[index].pid == pid: return index + 1 def get_arrival_time(self, pid): for process in self.processes_list: if process.pid == pid: return process.arrival_time def get_burst_time(self, pid): for index in range(len(self.pids)): if self.pids[index] == pid: return self.burst_times[index] def get_turnaround_time(self, pid): return self.get_departure_time(pid) - self.get_arrival_time(pid) def get_waiting_time(self, pid): return self.get_turnaround_time(pid) - self.get_burst_time(pid) # Populate Stats Table def display_stats(self): # Clear Table for r in range(self.stats_table.rowCount()): self.stats_table.removeRow(0) # Average Waiting/Turnaround Time total_waiting_time = 0 total_turnaround_time = 0 for process_row in range(len(self.processes_list)): self.stats_table.insertRow(process_row) pid = self.processes_list[process_row].pid finish_time = str(self.get_departure_time(pid)) waiting_time = str(self.get_waiting_time(pid)) total_waiting_time += int(waiting_time) turnaround_time = str(self.get_turnaround_time(pid)) total_turnaround_time += int(turnaround_time) item = QTableWidgetItem(pid) item.setTextAlignment(QtCore.Qt.AlignCenter) self.stats_table.setItem(process_row, 0, item) item = QTableWidgetItem(finish_time) item.setTextAlignment(QtCore.Qt.AlignCenter) self.stats_table.setItem(process_row, 1, item) item = QTableWidgetItem(turnaround_time) item.setTextAlignment(QtCore.Qt.AlignCenter) self.stats_table.setItem(process_row, 2, item) item = QTableWidgetItem(waiting_time) item.setTextAlignment(QtCore.Qt.AlignCenter) self.stats_table.setItem(process_row, 3, item) self.avg_waiting_label.setText( str(round(total_waiting_time / len(self.processes_list), 3))) self.avg_turnaround_label.setText( str(round(total_turnaround_time / len(self.processes_list), 3))) self.processes_list = [] # Draw Gantt Chart def draw_chart(self): self.clear_flag = True # Scene pen = QPen(Qt.lightGray) red_brush = QBrush(Qt.darkRed, Qt.SolidPattern) blue_brush = QBrush(Qt.darkBlue, Qt.SolidPattern) pink_brush = QBrush(Qt.darkMagenta, Qt.SolidPattern) green_brush = QBrush(Qt.darkGreen, Qt.SolidPattern) yellow_brush = QBrush(Qt.darkYellow, Qt.SolidPattern) cyan_brush = QBrush(Qt.darkCyan, Qt.SolidPattern) grey_brush = QBrush(Qt.darkGray, Qt.SolidPattern) black_brush = QBrush(Qt.black, Qt.SolidPattern) white_brush = QBrush(Qt.white, Qt.SolidPattern) self.scene = QGraphicsScene() rect_x = 0 for process in self.chart: if process == "Idle": self.scene.addRect(rect_x, -50, 20, 100, pen, white_brush) elif process.color == "red": self.scene.addRect(rect_x, -50, 20, 100, pen, red_brush) elif process.color == "blue": self.scene.addRect(rect_x, -50, 20, 100, pen, blue_brush) elif process.color == "pink": self.scene.addRect(rect_x, -50, 20, 100, pen, pink_brush) elif process.color == "green": self.scene.addRect(rect_x, -50, 20, 100, pen, green_brush) elif process.color == "yellow": self.scene.addRect(rect_x, -50, 20, 100, pen, yellow_brush) elif process.color == "cyan": self.scene.addRect(rect_x, -50, 20, 100, pen, cyan_brush) elif process.color == "grey": self.scene.addRect(rect_x, -50, 20, 100, pen, grey_brush) elif process.color == "black": self.scene.addRect(rect_x, -50, 20, 100, pen, black_brush) # Time axis labels text_item = QtWidgets.QGraphicsTextItem( str(int((rect_x + 20) / 20))) text_item.setPos(rect_x + 12, 50) self.scene.addItem(text_item) rect_x += 20 # Show Scene self.chart_view = QGraphicsView(self.scene, self.chart_view) self.gridLayout_2.addWidget(self.chart_view, 15, 0, 1, 2) #self.chart_view.setGeometry(QtCore.QRect(0, 0, 1000, 700)) self.chart_view.show() # Show Error Message Popup def popup(self, title, text): msg = QMessageBox() msg.setWindowTitle(title) msg.setText(text) msg.setIcon(QMessageBox.Warning) show_msg = msg.exec_() # Clear Button is Clicked def clear_clicked(self): self.stats_table.setRowCount(0) self.avg_turnaround_label.clear() self.avg_waiting_label.clear() if self.clear_flag: self.scene.clear() self.clear_flag = False # Add Button is Clicked def add_clicked(self): # Add table row self.table.insertRow(self.row) # Center Alignment for col in range(5): item = QtWidgets.QTableWidgetItem() item.setTextAlignment(QtCore.Qt.AlignCenter) self.table.setItem(self.row, col, item) # Create Drop-down menu for colors self.comboBox.append(QtWidgets.QComboBox()) self.comboBox[self.row].addItem("") self.comboBox[self.row].addItem("black") self.comboBox[self.row].addItem("grey") self.comboBox[self.row].addItem("blue") self.comboBox[self.row].addItem("cyan") self.comboBox[self.row].addItem("red") self.comboBox[self.row].addItem("pink") self.comboBox[self.row].addItem("green") self.comboBox[self.row].addItem("yellow") self.table.setCellWidget(self.row, 1, self.comboBox[self.row]) self.row += 1 # Remove Button is Clicked def remove_clicked(self): # Remove table row if self.row > 0: self.row -= 1 self.table.removeRow(self.row) self.comboBox.pop(self.row) # Simulate Button is Clicked def simulate_clicked(self): # Error Checking # Check if at least 1 process is provided if self.row == 0: self.popup("Process Selection", "Please Provide at least one Process.") return # Check that all mandatory table cells are provided # Also checks for data validation for row in range(self.table.rowCount()): for col in range(4): # Check if color cell if col == 1: if self.comboBox[row].currentText() != "": continue else: # Error Message self.popup("Invalid Input", "Please Fill All Essential Table Entries.") return # Empty Cells elif self.table.item(row, col).text() == "": # Error Message self.popup("Invalid Input", "Please Fill All Essential Table Entries.") return # Invalid Input elif not self.table.item(row, col).text().isdigit(): # Error Message self.popup("Invalid Input", "Table cells only accept numeric values.") return if not self.table.item(row, 4).text().isdigit() and self.table.item( row, 4).text() != "": # Error Message self.popup("Invalid Input", "Table cells only accept numeric values.") return # Take data from table self.processes_list = [] for row in range(self.table.rowCount()): pid = self.table.item(row, 0).text() color = self.comboBox[row].currentText() arrival = int(self.table.item(row, 2).text()) burst = int(self.table.item(row, 3).text()) if self.table.item(row, 4).text() != "": priority = int(self.table.item(row, 4).text()) else: priority = 0 self.processes_list.append( Process(pid, color, arrival, burst, priority)) # Get the desired algorithm selected_algorithm = self.algorithm_dropdown.currentText() # Populate one list with pids and another with corresponding burst times self.pids = [] self.burst_times = [] for process in self.processes_list: self.pids.append(process.pid) self.burst_times.append(process.burst_time) # First Come, First Served if selected_algorithm == "First Come, First Served": self.chart = CPU_SCHEDULER.first_come_first_served( self.processes_list) # Shortest Job First (Non) elif selected_algorithm == "Shortest Job First (Non Preemptive)": self.chart = CPU_SCHEDULER.shortest_job_first(self.processes_list, preemptive=0) # Shortest Job First (Pre) elif selected_algorithm == "Shortest Job First (Preemptive)": self.chart = CPU_SCHEDULER.shortest_job_first(self.processes_list, preemptive=1) # Priority (Non) elif selected_algorithm == "Priority (Non Preemptive)": # Priority fields check for row in range(self.table.rowCount()): if self.table.item(row, 4).text() == "": # Error Message self.popup("Invalid Input", "Please Fill Priority Cells.") return self.chart = CPU_SCHEDULER.priority(self.processes_list, preemptive=0) # Priority (Pre) elif selected_algorithm == "Priority (Preemptive)": # Priority fields check for row in range(self.table.rowCount()): if self.table.item(row, 4).text() == "": # Error Message self.popup("Invalid Input", "Please Fill Priority Cells.") return self.chart = CPU_SCHEDULER.priority(self.processes_list, preemptive=1) # Round Robin elif selected_algorithm == "Round Robin": if self.tq_in.text() == "": self.popup("Time Quantum Selection", "Please Specify the Desired Time Quantum.") return else: self.chart = CPU_SCHEDULER.round_robin(int(self.tq_in.text()), self.processes_list) # No Algorithm is checked else: self.popup("Algorithm Selection", "Please Select the Desired Algorithm.") return self.display_stats() self.draw_chart()
class SchedulerGUI(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent=parent) self.setupUi(self) self.schedule = sampleSchedule() self.activatedColumns = {} for key in self.schedule.columns: self.activatedColumns[key] = True self.lang = 'en' self.restore_buttons = [] self.restoreAllButton.clicked.connect(self.restoreAllColumns) self.translateDict = {} for widget in self.centralwidget.findChildren((QPushButton, QLabel)): langDict = {} for l in languages: langDict[l] = trans(widget.text(), l) key = widget self.translateDict[key] = langDict self.translateWidgets() self.language0Button.clicked.connect(partial(self.changeLang, 'en')) self.language1Button.clicked.connect(partial(self.changeLang, 'ru')) self.language2Button.clicked.connect(partial(self.changeLang, 'de')) self.drawAlarm = QTimer() self.drawAlarm.timeout.connect(self.drawAlarmFunc) self.drawAlarm.start(0.3) def closeEvent(self, event): quit() def resizeEvent(self, event): self.draw() def drawAlarmFunc(self): self.drawAlarm.stop() self.draw() def draw(self): self.scheduleScene = QGraphicsScene() self.activatedScene = QGraphicsScene() self.w = self.scheduleView.width() self.h = Y_SIDE * 24 self.h_a = self.activatedView.height() self.gridPen = QPen(QtCore.Qt.gray) for i in range(0, 24): self.scheduleScene.addLine(0, i * Y_SIDE, self.w, i * Y_SIDE) self.drawTimeTapes() cols = self.getActivatedColumns() if (len(cols) > 0): self.drawColumns(cols) self.scheduleView.setScene(self.scheduleScene) self.activatedView.setScene(self.activatedScene) def drawTimeTapes(self): for i in range(0, len(self.schedule.timeTapes)): self.scheduleScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h) self.activatedScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h_a) l = QLabel(self.schedule.timeTapes[i].name) l.move(WIDTH_TL * i, 0) self.activatedScene.addWidget(l) for j in range(0, 24): l = QLabel(self.schedule.timeTapes[i].labels[j]) l.move(WIDTH_TL * i, Y_SIDE * j) self.scheduleScene.addWidget(l) def drawColumns(self, cols): x_offset = WIDTH_TL * len(self.schedule.timeTapes) act_col_width = (self.w - x_offset) / len(cols) self.deactivateButtons = [] for i in range(0, len(cols)): self.scheduleScene.addLine(x_offset + act_col_width * i, 0, x_offset + act_col_width * i, self.h) self.activatedScene.addLine(x_offset + act_col_width * i, 0, x_offset + act_col_width * i, self.h_a) b = QPushButton(cols[i].name[self.lang]) b.move(x_offset + act_col_width * i, 0) b.clicked.connect(partial(self.deactivateColumn, cols[i].abr)) b.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) b.resize(act_col_width, self.h_a) b = self.activatedScene.addWidget(b) for event in cols[i].events: self.drawEvent(event, x_offset, act_col_width, i) def drawEvent(self, event, x_offset, col_width, x_loc): t0_f = timeStrToFloat(event.t0) t1_f = timeStrToFloat(event.t1) length = (t1_f - t0_f) * (self.h / 24) space = QtCore.QSizeF(col_width, length) r = QtCore.QRectF( QtCore.QPointF(x_offset + x_loc * col_width, t0_f * (self.h / 24)), space) pen = QtGui.QPen(QtCore.Qt.blue) brush = QtGui.QBrush(QtCore.Qt.blue) self.scheduleScene.addRect(r, pen, brush) font_size = MAX_EVENT_FONT_PT l_title = QLabel(event.title[self.lang]) l_title.move(x_offset + x_loc * col_width, t0_f * (self.h / 24)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = l_title.fontMetrics().boundingRect( l_title.text()).width() title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() while (title_height > length or title_width > col_width) and font_size > MIN_EVENT_FONT_PT: font_size -= 2 l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = l_title.fontMetrics().boundingRect( l_title.text()).width() title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() print(font_size, length, title_width, col_width) ''' l_title = QLabel(event.title[self.lang]) l_title.move(x_offset + x_loc * col_width, t0_f * (self.h/24)) l_time = QLabel(event.t0 + ' - ' + event.t1) if (length > 2 * LABEL_FONT_PT + 2): titleFont = QtGui.QFont(LABEL_FONT, LABEL_FONT_PT, QtGui.QFont.Bold) l_title.setFont(titleFont) title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() timeFont = QtGui.QFont(LABEL_FONT, LABEL_FONT_PT, QtGui.QFont.Bold) l_time.move(x_offset + i * act_col_width, t0_f * (self.h/24) + title_height + 1) l_time.setFont(timeFont) ''' self.scheduleScene.addWidget(l_title) #self.scheduleScene.addWidget(l_time) def getActivatedColumns(self): cols = [] for key in self.schedule.columns: if self.activatedColumns[key]: cols.append(self.schedule.columns[key]) cols = sorted(cols, key=lambda x: x.abr) return cols def getDeactivatedColumns(self): cols = [] for key in self.schedule.columns: if not self.activatedColumns[key]: cols.append(self.schedule.columns[key]) cols = sorted(cols, key=lambda x: x.abr) return cols def deactivateColumn(self, key): b = QPushButton(RESTORE[self.lang] + ' ' + self.schedule.columns[key].name[self.lang]) b.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.restoreButtonLayout.insertWidget(-1, b) b.clicked.connect(partial(self.activateColumn, key, b)) self.restore_buttons.append(b) self.activatedColumns[key] = False self.draw() def activateColumn(self, key, b): self.activatedColumns[key] = True self.draw() b.deleteLater() self.restore_buttons.remove(b) def restoreAllColumns(self): for key in self.activatedColumns: self.activatedColumns[key] = True for b in self.restore_buttons: b.deleteLater() self.restore_buttons = [] self.draw() def translateWidgets(self): for widget in self.centralwidget.findChildren((QPushButton, QLabel)): try: widget.setText(self.translateDict[widget][self.lang]) except KeyError: langDict = {} for l in languages: langDict[l] = trans(widget.text(), l) key = widget self.translateDict[key] = langDict widget.setText(self.translateDict[widget][self.lang]) def changeLang(self, lang): self.lang = lang self.translateWidgets() self.drawAlarm.start(1)
class RecordsetWindow(QWidget): dataDisplayRequest = pyqtSignal(str, int) dataUpdateRequest = pyqtSignal(str, Base) # sensorsColor = ['e0c31e', '14148c', '006325', '6400aa', '14aaff', 'ae32a0', '80c342', '868482'] def __init__(self, manager, recordset: list, parent=None): super(QWidget, self).__init__(parent=parent) self.UI = Ui_frmRecordsets() self.UI.setupUi(self) self.sensors = {} self.sensors_items = {} self.sensors_graphs = {} self.time_pixmap = False self.time_bar = None self.dbMan = manager self.recordsets = recordset # Init temporal browser self.timeScene = QGraphicsScene() self.UI.graphTimeline.setScene(self.timeScene) self.UI.graphTimeline.fitInView(self.timeScene.sceneRect(), Qt.KeepAspectRatio) self.UI.graphTimeline.time_clicked.connect(self.timeview_clicked) # Update general informations about recordsets self.update_recordset_infos() # Load sensors for that recordset self.load_sensors() self.UI.lstSensors.itemChanged.connect(self.sensor_current_changed) # self.UI.frmSensors.setFixedHeight(self.height()-50) def paintEvent(self, paint_event): if not self.time_pixmap: self.draw_recordsets() self.draw_sensors() self.draw_dates() self.draw_timebar() self.time_pixmap = True def resizeEvent(self, resize_event): self.draw_recordsets() self.draw_sensors() self.draw_dates() self.draw_timebar() def load_sensors(self): self.UI.lstSensors.clear() self.sensors = {} self.sensors_items = {} # Create sensor colors # colors = QColor.colorNames() colors = [ 'darkblue', 'darkviolet', 'darkgreen', 'darkorange', 'darkred', 'darkslategray', 'darkturquoise', 'darkolivegreen', 'darkseagreen', 'darkmagenta', 'darkkhaki', 'darkslateblue', 'darksalmon', 'darkorchid', 'darkcyan' ] # Filter "bad" colors for sensors """colors.remove("white") colors.remove("black") colors.remove("transparent") colors.remove("red") colors.remove("green")""" # shuffle(colors) color_index = 0 if len(self.recordsets) > 0: for sensor in self.dbMan.get_sensors(self.recordsets[0]): self.sensors[sensor.id_sensor] = sensor for sensor in self.sensors.values(): index = -1 location_item = self.UI.lstSensors.findItems( sensor.location, Qt.MatchExactly) if len(location_item) == 0: item = QListWidgetItem(sensor.location) item.setFlags(Qt.NoItemFlags) item.setForeground(QBrush(Qt.black)) self.UI.lstSensors.addItem(item) else: index = self.UI.lstSensors.indexFromItem( location_item[0]).row() # Check if sensor is already there under that location item sensor_name = sensor.name + " (" + sensor.hw_name + ")" present = False if index != -1: for i in range(index, self.UI.lstSensors.count()): if self.UI.lstSensors.item(i).text() == sensor_name: present = True break if not present: item = QListWidgetItem(QIcon(':/OpenIMU/icons/sensor.png'), sensor_name) item.setCheckState(Qt.Unchecked) item.setForeground(QColor(colors[color_index])) item.setData(Qt.UserRole, sensor.id_sensor) # self.sensors_colors.append(colors[color_index]) self.sensors_items[sensor.id_sensor] = item color_index += 1 if color_index >= len(colors): color_index = 0 if index == -1: self.UI.lstSensors.addItem(item) else: self.UI.lstSensors.insertItem(index + 2, item) def update_recordset_infos(self): if len(self.recordsets) == 0: self.UI.lblTotalValue.setText("Aucune donnée.") self.UI.lblDurationValue.setText("Aucune donnée.") return start_time = self.recordsets[0].start_timestamp end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp # Coverage self.UI.lblTotalValue.setText( start_time.strftime('%d-%m-%Y %H:%M:%S') + " @ " + end_time.strftime('%d-%m-%Y %H:%M:%S')) # Duration self.UI.lblDurationValue.setText(str(end_time - start_time)) self.UI.lblCursorTime.setText(start_time.strftime('%d-%m-%Y %H:%M:%S')) def get_relative_timeview_pos(self, current_time): start_time = self.recordsets[0].start_timestamp.timestamp() end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp.timestamp() time_span = (end_time - start_time ) # Total number of seconds in recordsets if type(current_time) is datetime: current_time = current_time.timestamp() if time_span > 0: return ((current_time - start_time) / time_span) * self.UI.graphTimeline.width() else: return 0 def draw_dates(self): if len(self.recordsets) == 0: return # Computations start_time = self.recordsets[0].start_timestamp end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp # time_span = (end_time - start_time).total_seconds() # Total number of seconds in recordsets current_time = (datetime(start_time.year, start_time.month, start_time.day, 0, 0, 0) + timedelta(days=1)) # Drawing tools whitePen = QPen(Qt.white) blackPen = QPen(Qt.black) blackBrush = QBrush(Qt.black) # Date background rectangle self.timeScene.addRect(0, 0, self.UI.graphTimeline.width(), self.UI.graphTimeline.height() / 4, blackPen, blackBrush) # First date date_text = self.timeScene.addText(start_time.strftime("%d-%m-%Y")) date_text.setPos(0, -5) date_text.setDefaultTextColor(Qt.white) self.timeScene.addLine(0, 0, 0, self.UI.graphTimeline.height(), whitePen) # Date separators while current_time <= end_time: pos = self.get_relative_timeview_pos(current_time) self.timeScene.addLine(pos, 0, pos, self.UI.graphTimeline.height(), whitePen) date_text = self.timeScene.addText( current_time.strftime("%d-%m-%Y")) date_text.setPos(pos, -5) date_text.setDefaultTextColor(Qt.white) current_time += timedelta(days=1) def draw_recordsets(self): greenBrush = QBrush(QColor(212, 247, 192)) transPen = QPen(Qt.transparent) # Empty rectangle (background) self.timeScene.addRect(0, 0, self.UI.graphTimeline.width(), self.UI.graphTimeline.height(), transPen, QBrush(Qt.red)) self.timeScene.setBackgroundBrush(QBrush(Qt.black)) # Recording length for record in self.recordsets: start_pos = self.get_relative_timeview_pos(record.start_timestamp) end_pos = self.get_relative_timeview_pos(record.end_timestamp) span = end_pos - start_pos # print (str(span)) self.timeScene.addRect(start_pos, 0, span, self.UI.graphTimeline.height(), transPen, greenBrush) self.UI.graphTimeline.update() def draw_sensors(self): if len(self.sensors) == 0: return bar_height = (3 * (self.UI.graphTimeline.height() / 4)) / len(self.sensors) # for sensor in self.sensors: i = 0 for sensor in self.sensors.values(): sensorBrush = QBrush( self.sensors_items[sensor.id_sensor].foreground()) sensorPen = QPen(Qt.transparent) for record in self.recordsets: datas = self.dbMan.get_all_sensor_data( sensor=sensor, recordset=record, channel=sensor.channels[0]) for data in datas: start_pos = self.get_relative_timeview_pos( data.timestamps.start_timestamp) end_pos = self.get_relative_timeview_pos( data.timestamps.end_timestamp) span = max(end_pos - start_pos, 1) self.timeScene.addRect( start_pos, i * bar_height + (self.UI.graphTimeline.height() / 4), span, bar_height, sensorPen, sensorBrush) i += 1 def draw_timebar(self): self.time_bar = self.timeScene.addLine(0, 0, 0, self.timeScene.height(), QPen(Qt.cyan)) @pyqtSlot(QListWidgetItem) def sensor_current_changed(self, item): sensor = self.sensors[item.data(Qt.UserRole)] timeseries = [] # Color map colors = [Qt.red, Qt.green, Qt.yellow, Qt.cyan] if item.checkState() == Qt.Checked: # Choose the correct display for each sensor graph = None channels = self.dbMan.get_all_channels(sensor=sensor) for channel in channels: # Will get all data (converted to floats) channel_data = [] for record in self.recordsets: channel_data += self.dbMan.get_all_sensor_data( recordset=record, convert=True, sensor=sensor, channel=channel) timeseries.append(self.create_data_timeseries(channel_data)) timeseries[-1]['label'] = channel.label if sensor.id_sensor_type == SensorType.ACCELEROMETER \ or sensor.id_sensor_type == SensorType.GYROMETER \ or sensor.id_sensor_type == SensorType.BATTERY \ or sensor.id_sensor_type == SensorType.LUX \ or sensor.id_sensor_type == SensorType.CURRENT \ or sensor.id_sensor_type == SensorType.BAROMETER \ or sensor.id_sensor_type == SensorType.MAGNETOMETER \ or sensor.id_sensor_type == SensorType.TEMPERATURE \ or sensor.id_sensor_type == SensorType.HEARTRATE \ or sensor.id_sensor_type == SensorType.ORIENTATION \ or sensor.id_sensor_type == SensorType.FSR: #graph = IMUChartView(self.UI.displayContents) graph = IMUChartView(self.UI.mdiArea) # graph.add_test_data() # Add series for series in timeseries: graph.add_data(series['x'], series['y'], color=colors.pop(), legend_text=series['label']) graph.set_title(item.text()) if sensor.id_sensor_type == SensorType.GPS: # graph = GPSView(self.UI.mdiArea) """base_widget = QWidget(self.UI.displayContents) base_widget.setFixedHeight(400) base_widget.setMaximumHeight(400)""" base_widget = self.UI.mdiArea graph = GPSView(base_widget) for data in channel_data: gps = GPSGeodetic() gps.from_bytes(data.data) if gps.latitude != 0 and gps.longitude != 0: graph.addPosition(data.timestamps.start_timestamp, gps.latitude / 1e7, gps.longitude / 1e7) graph.setCursorPositionFromTime( data.timestamps.start_timestamp) # print (gps) if graph is not None: self.UI.mdiArea.addSubWindow(graph).setWindowTitle(item.text()) self.sensors_graphs[sensor.id_sensor] = graph #self.UI.displayContents.layout().insertWidget(0,graph) graph.show() QApplication.instance().processEvents() graph.aboutToClose.connect(self.graph_was_closed) graph.cursorMoved.connect(self.graph_cursor_changed) #self.UI.displayArea.ensureWidgetVisible(graph) # self.UI.displayArea.verticalScrollBar().setSliderPosition(self.UI.displayArea.verticalScrollBar().maximum()) # self.tile_graphs_vertically() self.UI.mdiArea.tileSubWindows() else: # Remove from display try: if self.sensors_graphs[sensor.id_sensor] is not None: self.UI.mdiArea.removeSubWindow( self.sensors_graphs[sensor.id_sensor].parent()) self.sensors_graphs[sensor.id_sensor].hide() self.sensors_graphs[sensor.id_sensor] = None # self.tile_graphs_vertically() self.UI.mdiArea.tileSubWindows() except KeyError: pass @pyqtSlot(QObject) def graph_was_closed(self, graph): for sensor_id, sensor_graph in self.sensors_graphs.items(): if sensor_graph == graph: self.sensors_graphs[sensor_id] = None self.sensors_items[sensor_id].setCheckState(Qt.Unchecked) break # self.tile_graphs_vertically() self.UI.mdiArea.tileSubWindows() @pyqtSlot(float) def graph_cursor_changed(self, timestamp): for graph in self.sensors_graphs.values(): if graph is not None: graph.setCursorPositionFromTime(timestamp / 1000, False) pos = self.get_relative_timeview_pos(timestamp / 1000) self.time_bar.setPos(pos, 0) self.UI.lblCursorTime.setText( datetime.fromtimestamp(timestamp / 1000).strftime('%d-%m-%Y %H:%M:%S')) @pyqtSlot(int) def timeview_clicked(self, x): self.time_bar.setPos(x, 0) # Find time corresponding to that position timestamp = (x / self.UI.graphTimeline.width()) * ( self.recordsets[len(self.recordsets) - 1].end_timestamp - self. recordsets[0].start_timestamp) + self.recordsets[0].start_timestamp self.UI.lblCursorTime.setText(timestamp.strftime('%d-%m-%Y %H:%M:%S')) for graph in self.sensors_graphs.values(): if graph is not None: # try: graph.setCursorPositionFromTime(timestamp, True) # except AttributeError: # continue @timing def create_data_timeseries(self, sensor_data_list: list): time_values = [] data_values = [] for sensor_data in sensor_data_list: # print('sensor_data', sensor_data) # Will get a dict with keys: time, values vals = sensor_data.to_time_series() # print('vals is length', len(vals)) time_values.append(vals['time']) data_values.append(vals['values']) # print('time_values length', len(time_values)) # print('data_values length', len(data_values)) # Concat vectors time_array = np.concatenate(time_values) data_array = np.concatenate(data_values) # Test, remove first time # time_array = time_array - time_array[0] # print('time_array_shape, data_array_shape', time_array.shape, data_array.shape) # return data return {'x': time_array, 'y': data_array} @pyqtSlot() def on_process_recordset(self): # Display Process Window window = ProcessSelectWindow(self.dbMan, self.recordsets) window.setStyleSheet(self.styleSheet()) if window.exec() == QDialog.Accepted: self.dataUpdateRequest.emit("result", window.processed_data) self.dataDisplayRequest.emit( "result", window.processed_data.id_processed_data) def tile_graphs_horizontally(self): if self.UI.mdiArea.subWindowList() is None: return position = QPoint(0, 0) for window in self.UI.mdiArea.subWindowList(): rect = QRect( 0, 0, self.UI.mdiArea.width() / len(self.UI.mdiArea.subWindowList()), self.UI.mdiArea.height()) window.setGeometry(rect) window.move(position) position.setX(position.x() + window.width()) def tile_graphs_vertically(self): if self.UI.mdiArea.subWindowList() is None: return position = QPoint(0, 0) for window in self.UI.mdiArea.subWindowList(): rect = QRect( 0, 0, self.UI.mdiArea.width(), self.UI.mdiArea.height() / len(self.UI.mdiArea.subWindowList())) window.setGeometry(rect) window.move(position) position.setY(position.y() + window.height())
class Paint(QGraphicsView): def __init__(self): QGraphicsView.__init__(self) self.setSceneRect(QRectF(self.viewport().rect())) self.scene = QGraphicsScene() self.paint = False self.put_clusters = False self.isdelete = False self.coords_points = [] self.coords_clusters = [] self.clusters = [] self.points = [] def tools(self, e): x = e.x() y = e.y() if self.paint: brush = QBrush(Qt.SolidPattern) if self.put_clusters: pen = QPen(Qt.blue) self.coords_clusters.append([x, y]) self.clusters.append(self.scene.addEllipse(x, y, 15, 15, pen, brush)) self.scene.addItem(self.clusters[-1]) self.setScene(self.scene) else: pen = QPen(Qt.black) self.coords_points.append([x, y]) self.points.append(self.scene.addEllipse(x, y, 8, 8, pen, brush)) self.scene.addItem(self.points[-1]) self.setScene(self.scene) if self.isdelete: _ = [self.scene.removeItem(item) for item in self.items()] self.isdelete = False def mousePressEvent(self, event): e = QPointF(self.mapToScene(event.pos())) self.tools(e) def redraw_points(self, coords_poins): colors = {0: Qt.black, 1: Qt.green, 2: Qt.cyan, 3: Qt.yellow, 4: Qt.gray, 5: Qt.magenta, 6: Qt.red, 7:Qt.darkYellow} set = [] for i in [list(product([i], set)) for i, set in coords_poins.items()]: set.extend(i) _ = [self.scene.removeItem(item) for item in self.points] self.points.clear() self.scene.clearFocus() brush = QBrush(Qt.SolidPattern) pen = QPen() for point in set: pen.setColor(colors[point[0] % 8]) self.points.append(self.scene.addRect(point[1][0], point[1][1], 10, 10, pen, brush)) self.scene.addItem(self.points[-1])
class Battlefield(QGraphicsView): """The graphical battlefield.""" click = pyqtSignal(int) start = pyqtSignal() stop = pyqtSignal() def __init__(self, path: str): super().__init__() self.load_from_file(path) self.possible_colors = {"health": 0, "strength": 1, "braveness": 2} self.unit_size = 10 self.scene = QGraphicsScene() self.grid_size = 50 self.colormap = 0 self.background = QPixmap("gui/fond.png") self.zoom_level = 1 self.selected_unit = 0 self.edit = False self.simu = False self.wait = False self.mousePressEvent = self.on_mousePressEvent self.mouseMoveEvent = self.on_mouseMoveEvent self.mouseReleaseEvent = self.on_mouseReleaseEvent self.setGeometry(300, 300, self.grid_size * 10, self.grid_size * 10) self.setScene(self.scene) self.show() self.draw() def get_specs_tables(self): SPECS = [[[], []], [[], []], [[], []]] for i in range(self.size): speci = [[0, 0], [0, 0], [0, 0], [0, 0]] for unit in self.simulation.units(i): speci[0][unit.side] += 1 speci[1][unit.side] += unit.health speci[2][unit.side] += unit.strength speci[3][unit.side] += unit.braveness for j in range(3): for k in range(2): SPECS[j][k].append(speci[j + 1][k] / speci[0][k]) return SPECS def load_from_file(self, path: str): self.simulation = read_battle(path) self._state = 0 self._size = self.simulation.size def update(self, state_step: int): """Update the graphics and the grid between two steps.""" step_validity = 0 <= self._state + state_step < self.simulation.size if step_validity: self._state += state_step self.draw() return step_validity def go_to_state(self, state): """Move animation to given state.""" if 0 <= state < self.simulation.size: self._state = int(state) self.draw() def zoom(self, precision: float): """Zoom in on the picture.""" self.zoom_level *= precision self.resetCachedContent() self.draw() def get_unit(self, index: int): """Access specific unit.""" return self.simulation.units(self._state)[index] @property def size(self): """Get the size of the simulation.""" return self._size @property def state(self): """Get the current state.""" return self._state def change_colormap(self, color: str): """Change the colormap.""" if color in self.possible_colors: self.colormap = self.possible_colors[color] self.draw() def unit_position(self, unit): """Get screen position of unit.""" return (unit.coords + 10) * self.unit_size * self.zoom_level def on_mousePressEvent(self, event): pos = self.mapToScene(event.pos()) click = np.array((pos.x(), pos.y())) for i, unit in enumerate(self.simulation.units(self.state)): unit_pos = self.unit_position(unit) if np.all(unit_pos <= click) and np.all( click <= unit_pos + self.unit_size): self.click.emit(i) self.selected_unit = i self.draw() break else: # no unit found under pointer pos = event.pos() self.centerOn(pos.x(), pos.y()) def on_mouseMoveEvent(self, event): if self.edit: self.draw() pos = self.mapToScene(event.pos()) self.scene.addRect(pos.x(), pos.y(), self.unit_size, self.unit_size, QPen(), QBrush(QColor(0, 255, 0, 125))) QTest.qWait(10) def on_mouseReleaseEvent(self, event): if self.edit: pos = self.mapToScene(event.pos()) new_x = (pos.x() / (self.zoom_level * self.unit_size)) - 10 new_y = (pos.y() / (self.zoom_level * self.unit_size)) - 10 self.simulation.units( self.state)[self.selected_unit].coords = np.array( [new_x, new_y]) self.draw() if self.simu: self.instant_export() def change_mod(self): self.edit = not (self.edit) def change_simu(self): self.simu = not (self.simu) def gen_color(self, index, unit): """Generate a colormap for unit.""" def specs(unit): if not unit.is_centurion: return [unit.health, unit.strength, unit.braveness] return [0, 0, 0] max_val = max( [specs(unit)[index] for unit in self.simulation.units(0)]) shade = 150 * (specs(unit)[index] / max_val) + 105 color = [0, 0, 0] color[2 * unit.side] = shade return QColor(*color) def draw_unit(self, unit, pen, brush): position = self.unit_position(unit) if unit.reach >= 5: self.scene.addEllipse(*position, *[self.unit_size] * 2, pen, brush) else: self.scene.addRect(*position, *[self.unit_size] * 2, pen, brush) def draw_image(self, image): def shape(dim): return int(dim * (1 + self.zoom_level)) self.scene.addPixmap( image.scaled(*map(shape, (image.width(), image.height())))) def draw(self): """Draw the units and background.""" self.scene.clear() self.draw_image(self.background) # shuffle so that we also see blue units state = self.simulation.units(self.state) for unit in state: if not unit.is_dead: if not unit.is_centurion: color = self.gen_color(self.colormap, unit) else: if unit.side == 0: color = QColor(255, 0, 0) else: color = QColor(0, 0, 255) self.draw_unit(unit, QPen(), QBrush(color)) self.draw_unit(state[self.selected_unit], QPen(), QBrush(QColor(0, 255, 0))) def export(self, name): """To export the current state""" if not (self.wait): self.wait = True self.scene.addRect( -10, -10, int(self.background.width() * (1 + self.zoom_level)), int(self.background.height() * (1 + self.zoom_level)), QPen(), QBrush(QColor(255, 255, 255))) loading = QLabel() gif_load = QMovie("gui/loading.gif") loading.setMovie(gif_load) gif_load.start() self.scene.addWidget(loading) QTest.qWait(200) make_battle(self.simulation.state(self.state), name) QTest.qWait(200) self.draw() self.wait = False def instant_export(self): if not (self.wait): self.export("data/new.txt") self.load_from_file("data/new.txt")
class CircuitDiagramView(QGraphicsView): mousePress = pyqtSignal(tuple, tuple, name='mousePress') mouseMove = pyqtSignal(tuple, tuple, name='mouseMove') mouseRelease = pyqtSignal(tuple, tuple, name='mouseRelease') def __init__(self, parent=None): QGraphicsView.__init__(self, parent) self._model = None self.controller = None self.setAcceptDrops(True) # setup & render circuit diagram grid self.scene = QGraphicsScene() self.setScene(self.scene) self._shouldShowSelection = False self._selection = None self._dragging = False self.mousePosition = None self.draggingStart = None self.render() @property def shouldShowSelection(self): return self._shouldShowSelection @shouldShowSelection.setter def shouldShowSelection(self, value): if self.shouldShowSelection is not value and value is not None: self._shouldShowSelection = value self.render() @property def model(self): return self._model @model.setter def model(self, value): self._model = value self.model.modelChanged.connect(self.render) @property def selection(self): return self._selection @selection.setter def selection(self, value): if self.selection is not value: self._selection = value self.render() @property def dragging(self): return self._dragging @dragging.setter def dragging(self, value): self._dragging = value self.render() def componentTypeToImageName(self, componentType): dictionary = { ComponentType.Battery: "assets/battery.png", ComponentType.Resistor: "assets/resistor.png", ComponentType.Voltmeter: "assets/voltmeter.png", ComponentType.Ammeter: "assets/ammeter.png", ComponentType.Switch: "assets/switch-off.png", ComponentType.Bulb: "assets/bulb-off.png", ComponentType.Button: "assets/button-off.png", } return dictionary[componentType] def componentToImage(self, component): if component.type == ComponentType.Wire: image = QPixmap("assets/icon.png").scaled(self.blockSideLength, self.blockSideLength) if component.numberOfConnections() == 1: image = QPixmap("assets/wire-top.png").scaled(self.blockSideLength, self.blockSideLength) if component.connections[Direction.Right] is not None: image = image.transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Bottom] is not None: image = image.transformed(QtGui.QTransform().rotate(180)) elif component.connections[Direction.Left] is not None: image = image.transformed(QtGui.QTransform().rotate(270)) elif component.numberOfConnections() == 2: if component.connections[Direction.Left] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength) elif component.connections[Direction.Top] is not None and component.connections[Direction.Bottom] is not None: image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Top] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength) elif component.connections[Direction.Top] is not None and component.connections[Direction.Left] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(270)) elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Left] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(180)) elif component.numberOfConnections() == 3: image = QPixmap("assets/wire-left-top-right.png").scaled(self.blockSideLength, self.blockSideLength) if component.connections[Direction.Left] is None: image = image.transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Top] is None: image = image.transformed(QtGui.QTransform().rotate(180)) elif component.connections[Direction.Right] is None: image = image.transformed(QtGui.QTransform().rotate(270)) return image else: imageName = "assets/wire-right.png" if component.type == ComponentType.Bulb: if component.isOn(): imageName = "assets/bulb-on.png" else: imageName = "assets/bulb-off.png" elif component.type == ComponentType.Switch: if component.closed: imageName = "assets/switch-on.png" else: imageName = "assets/switch-off.png" elif component.type == ComponentType.Button: if component.closed: imageName = "assets/button-on.png" else: imageName = "assets/button-off.png" else: imageName = self.componentTypeToImageName(component.type) return QPixmap(imageName).scaled(self.blockSideLength, self.blockSideLength) def mouseCoordinatesToBlockIndex(self, x, y): if self.model is None or x < self.startingX or y < self.startingY or x > self.startingX + self.model.gridSize * self.blockSideLength or y > self.startingY + self.model.gridSize * self.blockSideLength: return (-1, -1) else: return (int((x - self.startingX) / self.blockSideLength), int((y - self.startingY) / self.blockSideLength)) def blockIndexToCoordinate(self, x, y): return (self.startingX + self.blockSideLength * x, self.startingY + self.blockSideLength * y) def mousePressEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mousePress.emit(index, (event.x(), event.y())) def dragEnterEvent(self, event): event.acceptProposedAction() def dragMoveEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y()) self.mouseMove.emit(index, (event.pos().x(), event.pos().y())) def dropEvent(self, event): event.acceptProposedAction() index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y()) self.mouseRelease.emit(index, (event.pos().x(), event.pos().y())) def mouseMoveEvent(self, event): self.mousePosition = (event.x(), event.y()) if self.dragging: self.render() index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mouseMove.emit(index, (event.pos().x(), event.pos().y())) def mouseReleaseEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mouseRelease.emit(index, (event.pos().x(), event.pos().y())) def resizeEvent(self, event): self.render() def render(self): if self.model is not None: self.scene.clear() self.renderCircuitDiagramGrid() self.renderComponents() def renderComponents(self): if self.model is not None: for component in self.model.components: pixmap = self.componentToImage(component) pixmapItem = self.scene.addPixmap(pixmap) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) pixmapItem.setOffset(offset[0],offset[1]) pixmapItem.setTransformationMode(Qt.SmoothTransformation) if component is self.selection: if self.dragging: renderPosition = (self.startingX + self.selection.position[0] * self.blockSideLength + self.mousePosition[0] - self.draggingStart[0], self.startingY + self.selection.position[1] * self.blockSideLength + self.mousePosition[1] - self.draggingStart[1]) pixmapItem.setOffset(renderPosition[0], renderPosition[1]) elif self.shouldShowSelection: pen = QPen(QBrush(QColor(0,0,255,100)), 2, Qt.DashLine) self.scene.addRect(self.startingX + component.position[0] * self.blockSideLength, self.startingY + component.position[1] * self.blockSideLength, self.blockSideLength, self.blockSideLength, pen) if component.type is ComponentType.Ammeter: font = QFont("Arial", self.blockSideLength/3.5) reading = self.scene.addText(str("%.2f" % component.current) + "A", font) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4) elif component.type is ComponentType.Voltmeter: font = QFont("Arial", self.blockSideLength/3.5) reading = self.scene.addText(str("%.2f" % component.voltage) + "V", font) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4) def renderCircuitDiagramGrid(self): pen = QPen(QBrush(QColor(200,200,200,255)), 1) pen2 = QPen(QBrush(QColor(100,100,100,255)), 3) width = self.width() height = self.height() self.blockSideLength = width / (self.model.gridSize + 2) if width < height else height / (self.model.gridSize + 2) # draw vertical lines currentX = width / 2 self.startingX = currentX - (self.model.gridSize / 2) * self.blockSideLength while currentX - self.blockSideLength >= 0: currentX -= self.blockSideLength while currentX < width: self.scene.addLine(currentX, 1, currentX, height - 1, pen) currentX += self.blockSideLength # draw horizontal lines currentY = height / 2 self.startingY = currentY - (self.model.gridSize / 2) * self.blockSideLength while currentY - self.blockSideLength >= 0: currentY -= self.blockSideLength while currentY < height: self.scene.addLine(1, currentY, width - 1, currentY, pen) currentY += self.blockSideLength self.scene.addLine(self.startingX, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, pen2) self.scene.addLine(self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2) self.scene.addLine(self.startingX, self.startingY, self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, pen2) self.scene.addLine(self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2)
app = QApplication(sys.argv) rs = QRectF(0, 0, 100, 100) ro = QRectF(-1, -1, 3, 2) s = QGraphicsScene(rs) v = QGraphicsView(s) v.setGeometry(20, 20, 600, 600) v._origin_u = True v._origin_l = True print('screenGeometry():', app.desktop().screenGeometry()) print('scene rect=', s.sceneRect()) v.fitInView(rs, Qt.KeepAspectRatio) # Qt.IgnoreAspectRatio Qt.KeepAspectRatioByExpanding Qt.KeepAspectRatio s.addRect(rs, pen=QPen(Qt.black, 0, Qt.SolidLine), brush=QBrush(Qt.yellow)) s.addRect(ro, pen=QPen(Qt.black, 0, Qt.SolidLine), brush=QBrush(Qt.red)) ruler1 = FWRuler(v, 'L') ruler2 = FWRuler(v, 'D') ruler3 = FWRuler(v, 'U') ruler4 = FWRuler(v, 'R') v.setWindowTitle("My window") v.setContentsMargins(0,0,0,0) v.show() app.exec_() ruler1.remove() ruler2.remove() ruler3.remove()
class AMANDisplay(QGraphicsView): def __init__(self): super().__init__() self.setGeometry(0, 0, 500, 600) self.setStyleSheet('background-color:#233370') self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, 500, 600) # Timeline boundaries pen = QPen(QColor('white')) brush = QBrush(QColor('#233370')) self.scene.addLine(220, 0, 220, 600, pen) self.scene.addLine(280, 0, 280, 600, pen) self.scene.addLine(0, 30, 500, 30, pen) timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush) timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True) # Timeline scale self.timeline = QGraphicsItemGroup() self.timeline.setParentItem(timelinebox) self.timeticks = [] for i in range(40): y = 15 * i w = 6 if i % 5 == 0: w = 10 self.timeticks.append(self.scene.addText('%02d' % (40 - i), QFont('Courier', 10))) self.timeticks[-1].setPos(240, y - 10) self.timeticks[-1].setDefaultTextColor(QColor('white')) self.timeline.addToGroup(self.timeticks[-1]) self.timeline.addToGroup(self.scene.addLine(220, y, 220 + w, y, pen)) self.timeline.addToGroup(self.scene.addLine(280 - w, y, 280, y, pen)) self.lrwy = self.scene.addText('18R', QFont('Arial', 20, 50)) self.lrwy.setPos(1, 1) self.lrwy.setDefaultTextColor(QColor('white')) # Finalize self.setScene(self.scene) self.show() def update(self, simt, data): # data has: ids, iafs, eats, etas, delays, rwys, spdratios # First delete old labels for key, in self.aircraft.keys: if key not in data.ids: # del label del self.aircraft[key] for i in len(data.ids): if data.ids[i] not in self.aircraft: # self.aircraft[data.ids[i]] = QLabel() pass # Generate the new label text and position newtext = '<font color=Red>bla</font>' # veranderen lbl = self.aircraft[data.ids[i]] lbl.setText(newtext) lbl.move(posx, posy) # move in pixels
class MainWindow(QMainWindow): def __init__(self, parent: QWidget=None) -> None: super(MainWindow, self).__init__(parent) uic.loadUi(os.path.join(getResourcesPath(), 'ui', 'mainwindow.ui'), self) self.actionExit.triggered.connect(QApplication.quit) self.actionLoad_G_Code.triggered.connect(self.askGCodeFile) self.actionPrint.triggered.connect(self.actionPrintSlot) self.actionClear.triggered.connect(self.actionClearSlot) self.actionZoomIn.triggered.connect(self.zoomIn) self.actionZoomOut.triggered.connect(self.zoomOut) self.actionResetZoom.triggered.connect(self.resetZoom) self.actionSetPenWidth.triggered.connect(self.askPenWidth) self.actionShowMovement.toggled.connect(self.actionShowMovementSlot) self.checkBoxActionShowMovement = QCheckBox( self.actionShowMovement.text(), self.toolBar) self.checkBoxActionShowMovement.setChecked(True) # noinspection PyUnresolvedReferences self.checkBoxActionShowMovement.toggled.connect( self.actionShowMovementSlot) self.toolBar.insertWidget(self.actionSetMoveLineColor, self.checkBoxActionShowMovement) self.actionSetMoveLineColor.triggered.connect( self.actionSetMoveLineColorSlot) self.zoomFactor = 1 self._precision = 1 self._moveLineColor = Qt.green self.material = None self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.graphicsView.scale(1, -1) self.graphicsView.setBackgroundBrush(QBrush(Qt.lightGray)) self.clearScene() self.updateStatusBar() @property def moveLineColor(self) -> QColor: return self._moveLineColor @moveLineColor.setter def moveLineColor(self, new_color: QColor) -> None: self._moveLineColor = new_color for item in self.scene.items(): if isinstance(item, QGraphicsMovementLineItem): item.color = self.moveLineColor @property def precision(self) -> number: return self._precision @precision.setter def precision(self, new_precision: number) -> None: self._precision = new_precision for item in self.scene.items(): if isinstance(item, PenWidthSettable) and\ isinstance(item, QGraphicsItem): item.penWidth = self.precision self.updateStatusBar() def actionPrintSlot(self) -> None: printer = QPrinter() printer.setPageOrientation(QPageLayout.Landscape) if QPrintDialog(printer).exec_(): painter = QPainter(printer) painter.setRenderHint(QPainter.Antialiasing) view = QGraphicsView() view.setScene(self.scene) view.setSceneRect(QRectF(0, 0, 290, 200)) view.fitInView(QRectF(0, 0, 290, 200), Qt.KeepAspectRatio) view.scale(1, -1) view.render(painter) del painter # necessary, thanks Qt def updateStatusBar(self) -> None: # noinspection PyUnresolvedReferences self.statusBar.showMessage('Current pen width: %.3f' % self._precision) def actionShowMovementSlot(self, toggle: bool) -> None: self.checkBoxActionShowMovement.setChecked(toggle) self.actionShowMovement.setChecked(toggle) for item in self.scene.items(): if isinstance(item, QGraphicsMovementLineItem): item.setVisible(toggle) def askPenWidth(self) -> None: # noinspection PyCallByClass, PyTypeChecker res = QInputDialog.getDouble(self, 'Change pen width', 'Enter new pen width:', self.precision, -10000, 10000, 3) if res[1]: self.precision = res[0] def actionClearSlot(self) -> None: if self.askClearScene(): self.clearScene() def actionSetMoveLineColorSlot(self) -> None: # Inspector doesn't understand Qt's static methods # noinspection PyCallByClass,PyTypeChecker color = QColorDialog.getColor(self.moveLineColor, self, 'Select new move line color') if QColor.isValid(color): self.moveLineColor = color def askClearScene(self) -> bool: msgbox = QMessageBox(self) msgbox.setText('This will clear the area.') msgbox.setInformativeText('Are you sure you want to continue?') msgbox.setStandardButtons( QMessageBox.Cancel | QMessageBox.Ok) msgbox.setDefaultButton(QMessageBox.Cancel) ret = msgbox.exec() if ret == QMessageBox.Ok: return True return False def clearScene(self) -> None: self.scene.clear() self.precision = 1 self.updateStatusBar() self.material = self.scene.addRect(QRectF(0, 0, 290, 200)) self.material.setPen(QPen(Qt.white)) self.material.setBrush(QBrush(Qt.white)) def askGCodeFile(self) -> None: # noinspection PyCallByClass, PyTypeChecker filetuple = QFileDialog.getOpenFileName(self, 'Select G Code file', getResourcesPath(), 'G Code files (*.gcode);;' 'Text files (*.txt);;' 'All Files (*.*)') if filetuple: if os.path.isfile(filetuple[0]): self.loadGCode(filetuple[0]) def zoomIn(self) -> None: self.graphicsView.scale(1.15, 1.15) self.zoomFactor *= 1.15 def zoomOut(self) -> None: self.graphicsView.scale(1.0 / 1.15, 1.0 / 1.15) self.zoomFactor /= 1.15 def resetZoom(self) -> None: self.graphicsView.scale(1.0 / self.zoomFactor, 1.0 / self.zoomFactor) self.zoomFactor = 1 def loadGCode(self, filename: str) -> None: rawSteps = [] # a step is tuple of str (command) and dict of arg -> value # eg ('G1', {'X': 0}) with open(filename) as f: for index, line in enumerate(f): line = line.split(';', 1)[0] if not line: continue splitted = line.strip().split(' ') cmd = splitted[0] packedArgs = splitted[1:] args = {} for arg in packedArgs: args[arg[0]] = arg[1:] rawSteps.append((cmd, args)) for rawStep in rawSteps: cmd = rawStep[0] args = rawStep[1] if cmd == 'G2' or cmd == 'G3': try: args['I'] except KeyError: args['I'] = 0 try: args['J'] except KeyError: args['J'] = 0 self.execGCode(rawSteps) def execGCode(self, codes: List[GCode]) -> None: relative_mode = False prevX = 0 prevY = 0 for code in codes: cmd = code[0] args = code[1] if 'X' in args: x = float(args['X']) + (prevX if relative_mode else 0) else: x = prevX if 'Y' in args: y = float(args['Y']) + (prevY if relative_mode else 0) else: y = prevY if cmd == 'G0': line = QGraphicsMovementLineItem( line=QLineF(prevX, prevY, x, y), color=self._moveLineColor, penWidth=self.precision) if not self.checkBoxActionShowMovement.isChecked(): line.setVisible(False) self.scene.addItem(line) elif cmd == 'G1': self.scene.addItem( QGraphicsColoredLineItem( line=QLineF(prevX, prevY, x, y), penWidth=self.precision)) elif cmd == 'G2' or cmd == 'G3': offsetX = float(args['I']) offsetY = float(args['J']) if offsetX == 0 and offsetY == 0: # only R given radius = float(args['R']) dx = x - prevX dy = y - prevY dist = math.sqrt(dx ** 2 + dy ** 2) h = math.sqrt((radius ** 2) - ((dist ** 2) / 4)) tmpx = dy * h / dist tmpy = -dx * h / dist ccw = (cmd == 'G3') if (ccw and radius > 0) or ((not ccw) and radius < 0): tmpx = -tmpx tmpy = -tmpy middleX = tmpx + (2 * x - dx) / 2 middleY = tmpy + (2 * y - dy) / 2 else: radius = math.sqrt(offsetX ** 2 + offsetY ** 2) middleX = prevX + offsetX middleY = prevY + offsetY rectBottomLeftX = middleX - radius rectBottomLeftY = middleY - radius rectLength = 2 * radius alpha = math.degrees(math.atan2(prevY - middleY, prevX - middleX)) beta = math.degrees(math.atan2(y - middleY, x - middleX)) if cmd == 'G2': if beta > alpha: if beta >= 180: beta -= 360 else: alpha += 360 elif cmd == 'G3': if beta < alpha: if alpha > 180: alpha -= 360 else: beta += 360 delta = alpha - beta if delta == 0: delta = 360 ellipse = QGraphicsArcItem(rectBottomLeftX, rectBottomLeftY, rectLength, rectLength, penWidth=self.precision) ellipse.setStartAngle(-alpha) ellipse.setSpanAngle(delta) self.scene.addItem(ellipse) elif cmd == 'G91': relative_mode = True elif cmd == 'G90': relative_mode = False elif cmd == 'G28': # reference drive + general init relative_mode = False x = -0.9 y = 242.3 prevX = x prevY = y