0

As you can see in the image below sometimes some letters don't show in text box or they might show earlier when the textbox is updated with other characters.

The only thing I do with the text is to use the function appendPlainText(text) with a certain message.

Does anyone know how to solve this issue ? If you need any code let me know.

enter image description here

Edit (Add code):

I have a file which runs the code for the study selected from the combo box which uses a log function that is also in another file.

utils.py

LOGGING_OPTIONS = {
    "level": logging.INFO,
    "format": "<%(asctime)s | [%(levelname)s] | %(message)s",
    "format_log_container": "<%(asctime)s> %(message)s",
    "datefmt": "%H:%M:%S",
    "handlers": [logging.StreamHandler()],
}

logging.basicConfig(
    level=LOGGING_OPTIONS["level"],
    format=LOGGING_OPTIONS["format"],
    handlers=LOGGING_OPTIONS["handlers"],
)
logger = logging.getLogger()

def log(message, level=logging.INFO):
    if level == logging.INFO:
        logger.info(f"{message}")
    elif level == logging.ERROR:
        logger.error(f"{message}")

def delete_sheets(workbook, file_path, sheet_names):
    for sheet_name in sheet_names:
        if sheet_name in workbook.sheetnames:
            log(f"Deleting sheet: {sheet_name}")
            workbook.remove(workbook[sheet_name])

    workbook.save(file_path)

This log function is used everywhere when I want to log something.

dta_302.py - file with study code

def main_302(file_path):
  try:
      dta_sheet_names = [] # I get these names from an object
      workbook = load_workbook(file_path)
      delete_sheets(workbook, file_path, dta_sheet_names) # Is in utils file
  except IndexError:
      log("Could not load the file. Please introduce the correct path.")
  except Exception as error:
      log(error, logging.ERROR)

gui.py - file that manages the gui

class QtLogHandler(logging.Handler):
    def __init__(self, widget):
        super(QtLogHandler, self).__init__()
        self.widget = widget

    def emit(self, record):
        msg = self.format(record)
        self.widget.appendPlainText(msg)


class Signals(QObject):
    started = Signal()
    finished = Signal()


class Runnable(QRunnable):
    def __init__(self, func=None, *args):
        super(Runnable, self).__init__()
        self.func = func
        self.args = args
        self.signals = Signals()

    @Slot()
    def run(self):
        if self.func:
            self.func(*self.args)
            self.signals.finished.emit()

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        studies = [""] # Options for combo box

        self.file_path = ""
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # logger handler
        self.logger_handler = QtLogHandler(self.ui.logTextContainer)
        self.logger_handler.setFormatter(
            logging.Formatter(
                LOGGING_OPTIONS["format_log_container"], LOGGING_OPTIONS["datefmt"]
            )
        )
        utils_logger.addHandler(self.logger_handler)

        # Process to read console output
        self.process = QProcess()
        self.process.readyReadStandardOutput.connect(self.handle_stdout)  # type: ignore
        self.process.readyReadStandardError.connect(self.handle_stderr)  # type: ignore

        self.ui.selectStudyComboBox.addItems(studies)

        self.ui.selectFileBtn.clicked.connect((self.select_file))  # type: ignore
        self.ui.submitBtn.setEnabled(False)
        self.ui.submitBtn.clicked.connect((self.start_submit))  # type: ignore

        # Worker
        self.threadpool = QThreadPool()
        self.worker = Runnable(self.submit)
        self.worker.setAutoDelete(False)
        self.worker.signals.finished.connect(self.restore_ui)

    def add_log_message(self, message):
        self.logger_handler.widget.appendPlainText(message)
        self.logger_handler.widget.ensureCursorVisible()

    def handle_stdout(self):
        message = self.process.readAllStandardOutput().data().decode()
        self.add_log_message(message.strip())

    def handle_stderr(self):
        message = self.process.readAllStandardError().data().decode()
        self.add_log_message(message.strip())

    def select_file(self):
        file_dialog = QFileDialog.getOpenFileName(
            self, filter="Excel Files (*.xls *.xlsx *.xlsm)"
        )

        self.file_path = file_dialog[0]
        self.ui.selectedFilePath.setText(file_dialog[0])

        if self.file_path:
            self.ui.submitBtn.setEnabled(True)

    def start_submit(self):
        self.ui.selectStudyComboBox.setEnabled(False)
        self.ui.selectFileBtn.setEnabled(False)
        self.ui.submitBtn.setEnabled(False)
        self.threadpool.start(self.worker)

    def submit(self):
        selected_study = self.ui.selectStudyComboBox.currentText()

        if selected_study == "LC-FAOD 302":
            start_time = time.time()
            main_302(self.file_path)
            end_time = time.time()
            log(f"Running time: {end_time - start_time} seconds")

    def restore_ui(self):
        self.ui.selectStudyComboBox.setEnabled(True)
        self.ui.selectFileBtn.setEnabled(True)
        self.ui.submitBtn.setEnabled(True)
        self.add_log_message("")
  • 1
    It seems to remove the capital D. Have you tried another font? – Nuno André Nov 09 '22 at 13:57
  • You're not trying to call that function from another thread, are you? If not, please provide a [mre]. – musicamante Nov 09 '22 at 13:59
  • @NunoAndré it happens with other letters and it only does this sometimes. Maybe it's a problem on how I'm trying to get the log messages. – Pedro Gomes Nov 09 '22 at 15:10
  • @musicamante thanks for trying to help. The messages that aren't showing are the messages saying "Writing x records..." and this ones are running in another thread. Since the code i'm running is from another file what i did was to use a logger in the GUI which captures what comes from the standard output. I don't think i can put a minimal reproducible example but i will edit my message and put the code that i'm using. Maybe that could help – Pedro Gomes Nov 09 '22 at 15:14
  • 1
    @PedroGomes widgets are not thread safe, they can *not* be accessed from other threads. You must use QThreads and custom signals. – musicamante Nov 09 '22 at 15:22
  • @musicamante I added all the code i'm using, if you could check now I would appreciate your help. I know widgets are not thread safe was actually having some problems with my app crashing as soon I was clicking the buttons and I've been reading and trying to learn how these things work. – Pedro Gomes Nov 09 '22 at 15:35
  • @musicamante if you ask me why I'm using a Runnable instead of Thread, it was just an experiment. I was using a QThread before but If I pressed the submit button after it completed once, after pressing a second time the app would close without any warning after the code was running for a bit. – Pedro Gomes Nov 09 '22 at 15:39
  • 1
    @PedroGomes I suppose you're trying the most voted answer [here](https://stackoverflow.com/q/28655198/2001654). Be aware that that answer is **not** valid for threading as pointed out by multiple comments. Use the answer that do consider this aspect. – musicamante Nov 10 '22 at 18:00
  • @musicamente this is more or less what i'm doing right now. But I will try to improve my logger class based on the answer you provided. – Pedro Gomes Nov 10 '22 at 18:31

0 Answers0