Python

Clock using PyQt

Q How do I pop a dialog with a clock using MicroStation Python?

A Here's a small Python program that uses the PyQt library. It shows a small dialog that displays a digital clock inside the MicroStation window …

Python Implementation

Here's the Python source code of the clock. It is derived from the Python clock example delivered with MicroStation 2024 …

# MicroStationClockRevised.py

import sys
import PyQt5
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QFont, QWindow
import time

import os
from MSPyBentley import *
from MSPyBentleyGeom import *
from MSPyECObjects import *
from MSPyDgnPlatform import *
from MSPyDgnView import *
from MSPyMstnPlatform import *

#
# This is a modified version of the Clock example delivered with MicroStation Python examples.
# I modified it because I found the use of timers very confusing: the original has two timers, both named 'timer'.
# One timer is the the clock that you can see when the app is active.
# The other timer is the one discussed below that enable the app and MicroStation to share the Windows messages.
# I've renamed the timer variables to make clarify their use: 'clockTimer' and 'messageLoopTimer'
#
# This demonstrates a PyQt5 UX window containing a clock which doesn't block
# the execution of MicroStation's input loop.
#
# Using Python call app.exec will not return out of the loop until the PyQt5 window is closed, this blocks
# the main application thread of MicroStation. Qt is a C based Ux framework whose timers will execute in the main event loop for the UX framework
#
# Registering a timer with a 0 start interval will cause the timer method to execute every time the Qt Windows event loop finishes.
# Calling PyCadInputQueue.PythonMainLoop from the timer will allow MicroStation's input loop to execute allowing use of the
# MicroStation UX whilst the Qt window is displayed.
#

def dump(obj):
  for attr in dir(obj):
    print("obj.%s = %r" % (attr, getattr(obj, attr)))

class MainWindow(QMainWindow):
    # Initialize the main window class
    def __init__(self):
        # Call the parent class's constructor to initialize the main window
        super().__init__()

        # Set the title of the main window
        self.setWindowTitle("MicroStation PyQt5 Clock")

        # Set the background color of the main window
        self.setStyleSheet (
            'background-color: #666666;'  # hex code for medium gray
        )

        # Set the size of the main window (x, y, width, height)
        self.setGeometry (
            0,  # initial x-coordinate
            0,  # initial y-coordinate
            240,  # width in pixels
            80   # height in pixels
        )

        # Make the main window stay on top of other windows
        self.setWindowFlags (Qt.WindowStaysOnTopHint)

        # Create a QLabel widget for displaying the clock time
        self.label = QLabel (
            time.strftime("%H:%M:%S"),  # format string for 24-hour time display
            self  # parent widget is the main window
        )

        # Set the text color of the label to white
        self.label.setStyleSheet ('color:white;')

        # Set the font of the label to Arial with size 40
        self.label.setFont (
            QFont ("Arial", 40)  # font family and size
        )

        # Adjust the size of the label widget to fit its contents
        self.label.adjustSize ()

        # Create a QTimer object for updating the clock time
        #self.timer = QTimer (self)
        self.clockTimer = QTimer (self)

        # Connect the timer's timeout signal to the updateClock method
        self.clockTimer.timeout.connect (self.updateClock)

        # Start the timer with an interval of 1 second (1000 milliseconds)
        self.clockTimer.start (1000)

    def updateClock(self):
        self.label.setText (time.strftime("%H:%M:%S"))

def updateMstn ():
    PyCadInputQueue.PythonMainLoop()

def MessageLoopTimer ():
    #   Timer updates MicroStation each second to ensure that this Python window does not monopolise the message loopx
    messageLoopTimer = QTimer()   # create a QTimer object for updating the message loop
    messageLoopTimer.timeout.connect(updateMstn)  # connect the timer's timeout signal to the updateMstn function
    messageLoopTimer.start()   # start the timer with an interval of 1 second (1,000 milliseconds)


if __name__ == "__main__":  # check if this script is being run directly (not imported as a module)
    app = QApplication.instance()   # get the existing application instance, if any

    if app is None:  # check if no application instance exists
        app = QApplication(sys.argv)   # create a new application instance with command-line arguments

    window = MainWindow()   # create an instance of the main window class
    window.show()   # show the main window

    #   Timer updates MicroStation each second to ensure that this Python window does not monopolise the message loop
    MessageLoopTimer ()

    app.exec()  # run the application's event loop until the window is closed

Questions

Post questions about MicroStation programming to the MicroStation Programming Forum.