Hidden "ADD" button keeps reappearing in the table when new rows are added

Hidden “ADD” button keeps reappearing when new rows are added to the PyQt5 table using “Enter Details”

This is the code:

import os
import sys
from PyQt5.QtWidgets import (
    QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QDateEdit, QTableWidget, QDateTimeEdit,
    QGroupBox, QFileDialog,
    QTableWidgetItem, QHeaderView, QMessageBox, QDesktopWidget, QDialog, QHBoxLayout, QSplitter, QInputDialog,
    QDialogButtonBox
)
from PyQt5.QtGui import QPalette, QPainterPath, QPainter, QImage
from PyQt5.QtCore import Qt
from PyQt5.QtCore import Qt, QDate
import openpyxl

app = QApplication(sys.argv)
#app.setStyleSheet(open("employee_details.css").read())  # Load the CSS here


class EmployeeDetailsApp(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Employee Details and Age")

        screen = QDesktopWidget().screenGeometry()
        width = int(screen.width() * 1)
        height = int(screen.height() * 1)
        self.setGeometry(int((screen.width() - width) / 2), int((screen.height() - height) / 2), width, height)

        self.layout = QVBoxLayout(self)

        # Create a splitter
        splitter = QSplitter(Qt.Horizontal)

        # Left side (Input fields and buttons)
        left_widget = QWidget(splitter)
        left_layout = QVBoxLayout(left_widget)

        self.create_input_fields(left_layout)

        # Right side (Table)
        right_widget = QWidget(splitter)
        right_layout = QVBoxLayout(right_widget)

        self.create_table(right_layout)

        # Add the splitter to the main layout
        self.layout.addWidget(splitter)

        # Set the splitter ratio to 20% - 80%
        sizes = [int(width * 0.25), int(width * 0.75)]
        splitter.setSizes(sizes)
        self.button_widgets = {}

        self.employee_details = None

    def create_input_fields(self, layout):
        self.doc_name_label = QLabel("Document Name:")
        self.doc_name_field = QLineEdit()

        self.doc_number_label = QLabel("Document Number:")
        self.doc_number_field = QLineEdit()

        self.name_label = QLabel("Part Number:")
        self.name_field = QLineEdit()

        self.issue_date_label = QLabel("Issue Date:")
        self.issue_date_field = QDateEdit()
        self.issue_date_field.setDate(QDate.currentDate())  # Set default value to today's date
        self.issue_date_field.setCalendarPopup(True)
        self.initial_date = self.issue_date_field.date()

        self.document_type_label = QLabel("Document Type:")
        self.document_type_field = QLineEdit()

        self.issued_by_label = QLabel("Issued By:")
        self.issued_by_field = QLineEdit()

        self.signature_label_issued = QLabel("Signature (Issued):")
        self.signature_button_issued = QPushButton("")
        self.signature_button_issued.clicked.connect(self.open_signature_dialog_issued)

        self.received_by_label = QLabel("Received By:")
        self.received_by_field = QLineEdit()

        self.signature_label_received = QLabel("Signature (Received):")
        self.signature_button_received = QPushButton("")
        self.signature_button_received.clicked.connect(self.open_signature_dialog_received)

        self.remark_label = QLabel("Remark:")
        self.remark_field = QLineEdit()

        self.enter_button = QPushButton("Enter Details")
        self.enter_button.clicked.connect(self.enter_details)

        layout.addWidget(self.doc_name_label)
        layout.addWidget(self.doc_name_field)
        layout.addWidget(self.doc_number_label)
        layout.addWidget(self.doc_number_field)
        layout.addWidget(self.name_label)
        layout.addWidget(self.name_field)
        layout.addWidget(self.issue_date_label)
        layout.addWidget(self.issue_date_field)
        layout.addWidget(self.document_type_label)
        layout.addWidget(self.document_type_field)
        layout.addWidget(self.issued_by_label)
        layout.addWidget(self.issued_by_field)
        layout.addWidget(self.signature_label_issued)
        layout.addWidget(self.signature_button_issued)
        layout.addWidget(self.received_by_label)
        layout.addWidget(self.received_by_field)
        layout.addWidget(self.signature_label_received)
        layout.addWidget(self.signature_button_received)
        layout.addWidget(self.remark_label)
        layout.addWidget(self.remark_field)
        layout.addWidget(self.enter_button)

    def create_table(self, layout):
        self.employee_table = QTableWidget()
        self.employee_table.setColumnCount(10)
        self.employee_table.setHorizontalHeaderLabels([
            "Document Name", "Document Number", "Part Number", "Issue Date", "Document Type",
            "Issued By", "Signature (Issued)", "Received By", "Signature(Received)", "Remark"
        ])

        # Set the size of each column
        column_sizes = [150, 150, 100, 100, 120, 120, 120, 150, 150, 200]  # Adjust sizes as needed
        for col, size in enumerate(column_sizes):
            self.employee_table.setColumnWidth(col, size)

        #self.employee_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        layout.addWidget(self.employee_table)


        # Create a QHBoxLayout for side-by-side placement
        hbox_layout = QHBoxLayout()

        # Create a QHBoxLayout for buttons
        actions_groupbox = QGroupBox("Actions")
        actions_layout = QVBoxLayout(actions_groupbox)

        self.save_button = QPushButton("Save to Excel")
        self.view_excel_data_button = QPushButton("View Excel Data")
        self.refresh_button = QPushButton("Refresh")

        actions_layout.addWidget(self.save_button)
        actions_layout.addWidget(self.view_excel_data_button)
        actions_layout.addWidget(self.refresh_button)

        hbox_layout.addWidget(actions_groupbox)

        self.save_button.clicked.connect(self.save_to_excel)
        self.view_excel_data_button.clicked.connect(self.view_excel_data)
        self.refresh_button.clicked.connect(self.refresh_table)

        # Create a QGroupBox for "Filter" section
        filter_groupbox = QGroupBox("Filter")
        filter_layout = QVBoxLayout(filter_groupbox)

        # Add filter-related widgets
        self.start_date_label = QLabel("Start Date:")
        self.start_date_field = QDateEdit()
        self.start_date_field.setDisplayFormat("yyyy-MM-dd")
        self.start_date_field.setCalendarPopup(True)

        self.end_date_label = QLabel("End Date:")
        self.end_date_field = QDateEdit()
        self.end_date_field.setDisplayFormat("yyyy-MM-dd")
        self.end_date_field.setCalendarPopup(True)

        self.document_name_label = QLabel("Document Name:")
        self.document_name_field = QLineEdit()

        self.filter_apply_button = QPushButton("Apply Filter")
        self.filter_apply_button.clicked.connect(self.apply_filter)

        filter_layout.addWidget(self.start_date_label)
        filter_layout.addWidget(self.start_date_field)
        filter_layout.addWidget(self.end_date_label)
        filter_layout.addWidget(self.end_date_field)
        filter_layout.addWidget(self.document_name_label)
        filter_layout.addWidget(self.document_name_field)
        filter_layout.addWidget(self.filter_apply_button)

        hbox_layout.addWidget(filter_groupbox)

        layout.addLayout(hbox_layout)

    def apply_filter(self):
        # Get the filter criteria
        start_date = self.start_date_field.date().toString("yyyy-MM-dd")
        end_date = self.end_date_field.date().toString("yyyy-MM-dd")
        document_name = self.document_name_field.text().lower()

        # Filter data based on criteria
        filtered_data = []
        for row in range(self.employee_table.rowCount()):
            row_data = [self.employee_table.item(row, col).text().lower() for col in
                        range(self.employee_table.columnCount())]
            row_visible = (
                    (start_date <= row_data[3] <= end_date) and  # Assuming date column is at index 3
                    (document_name in row_data[0])
            )
            if row_visible:
                filtered_data.append(row_data)

        # Create a new window to display the filtered data
        filter_result_window = FilterResultWindow(filtered_data)
        filter_result_window.exec_()

    def set_input_width(self, widget, percentage):
        width = int(self.width() * percentage)
        widget.setFixedWidth(width)

    def open_signature_dialog_issued(self, row):
        dialog = SignatureDialogIssued(self)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.hideiss(row)
            signature_text = dialog.get_signature()

    def open_signature_dialog_received(self, row):
        dialog = SignatureDialogReceived(self)
        result = dialog.exec_()
        if result == QDialog.Accepted:
            self.hiderec(row)
            signature_text = dialog.get_signature()

    def hiderec(self, row):
        self.button_widgets[row]["received"].hide()

    def hideiss(self, row):
        self.button_widgets[row]["issued"].hide()

    def enter_details(self):
        doc_name = self.doc_name_field.text()
        doc_number = self.doc_number_field.text()
        part_number = self.name_field.text()
        issue_date = self.issue_date_field.date().toString("yyyy-MM-dd")
        document_type = self.document_type_field.text()
        issued_by = self.issued_by_field.text()
        signature_issued = self.signature_button_issued.text()
        received_by = self.received_by_field.text()
        signature_received = self.signature_button_received.text()
        remark = self.remark_field.text()

        self.employee_details = (
            doc_name, doc_number, part_number, issue_date, document_type, issued_by, signature_issued, received_by,
            signature_received, remark)

        row_count = self.employee_table.rowCount()
        print(row_count)
        self.employee_table.insertRow(row_count)
        for col, value in enumerate(self.employee_details):
            self.employee_table.setItem(row_count, col, QTableWidgetItem(value))
            if col == 6:
                self.btn_widget1 = self.create_button_widgetissued(row_count, col)
                self.employee_table.setCellWidget(row_count, col, self.btn_widget1)
            elif col == 8:
                self.btn_widget2 = self.create_button_widgetrecieved(row_count, col)
                self.employee_table.setCellWidget(row_count, col, self.btn_widget2)

        self.employee_table.setRowHeight(row_count, 80)

        # Store the button widgets in the dictionary
        self.button_widgets[row_count] = {"issued": self.btn_widget1, "received": self.btn_widget2}

        self.clear_fields()

    def create_button_widgetissued(self, row, col):
        button_widget = QWidget(self)
        layout = QVBoxLayout(button_widget)

        add_button = QPushButton("Add", button_widget)
        add_button.clicked.connect(lambda _, r=row: self.open_signature_dialog_issued(r))

        layout.addWidget(add_button)
        layout.setAlignment(add_button, Qt.AlignCenter)

        return button_widget

    def create_button_widgetrecieved(self, row, col):
        button_widget = QWidget(self)
        layout = QVBoxLayout(button_widget)

        add_button = QPushButton("Add", button_widget)
        add_button.clicked.connect(lambda _, r=row: self.open_signature_dialog_received(r))

        layout.addWidget(add_button)
        layout.setAlignment(add_button, Qt.AlignCenter)

        return button_widget

    def save_to_excel(self):
        workbook = openpyxl.Workbook()
        sheet = workbook.active

        for row in range(self.employee_table.rowCount()):
            for col in range(self.employee_table.columnCount()):
                value = self.employee_table.item(row, col).text()
                sheet[chr(ord('A') + col) + str(row + 1)] = value

        workbook.save("employee_data.xlsx")
        self.clear_fields()

    def view_excel_data(self):
        try:
            os.startfile("employee_data.xlsx")
        except FileNotFoundError:
            QMessageBox.warning(self, "Error", "Employee data file not found.")

    def refresh_table(self):
        self.employee_table.setRowCount(0)

    def clear_fields(self):
        self.doc_name_field.clear()
        self.doc_number_field.clear()
        self.name_field.clear()
        self.issue_date_field.setDate(self.initial_date)
        self.document_type_field.clear()
        self.issued_by_field.clear()
        self.received_by_field.clear()
        self.signature_button_issued.setText("")
        self.signature_button_received.setText("")
        self.remark_field.clear()
        self.employee_details = None


class FilterResultWindow(QDialog):
    def __init__(self, filtered_data, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Filter Result")
        self.layout = QVBoxLayout()

        self.table = QTableWidget()
        self.table.setColumnCount(10)
        self.table.setHorizontalHeaderLabels([
            "Document Name", "Document Number", "Part Number", "Issue Date", "Document Type",
            "Issued By", "Signature (Issued)", "Received By", "Signature(Received)", "Remark"
        ])

        # Populate the filtered data into the table
        self.table.setRowCount(len(filtered_data))
        for row, data_row in enumerate(filtered_data):
            for col, value in enumerate(data_row):
                self.table.setItem(row, col, QTableWidgetItem(value))

        self.layout.addWidget(self.table)

        # Add a button to save filtered data to a new Excel file
        self.save_filtered_button = QPushButton("Save Filtered Data")
        self.save_filtered_button.clicked.connect(self.save_filtered_data)
        self.layout.addWidget(self.save_filtered_button)

        self.setLayout(self.layout)

    def save_filtered_data(self):
        workbook = openpyxl.Workbook()
        sheet = workbook.active

        # Write header row
        header = [
            "Document Name", "Document Number", "Part Number", "Issue Date", "Document Type",
            "Issued By", "Signature (Issued)", "Received By", "Signature(Received)", "Remark"
        ]
        for col, value in enumerate(header):
            sheet[chr(ord('A') + col) + "1"] = value

        # Write data rows
        for row, data_row in enumerate(self.get_table_data()):
            for col, value in enumerate(data_row):
                sheet[chr(ord('A') + col) + str(row + 2)] = value

        # Save the workbook
        try:
            file_dialog = QFileDialog(self)
            file_dialog.setAcceptMode(QFileDialog.AcceptSave)
            file_path, _ = file_dialog.getSaveFileName(self, "Save Filtered Data", "", "Excel Files (*.xlsx)")
            if file_path:
                workbook.save(file_path)
                QMessageBox.information(self, "Saved", "Filtered data saved successfully.")
        except Exception as e:
            QMessageBox.warning(self, "Error", f"An error occurred: {str(e)}")

    def get_table_data(self):
        # Helper function to get data from the table
        table_data = []
        for row in range(self.table.rowCount()):
            row_data = [self.table.item(row, col).text() for col in range(self.table.columnCount())]
            table_data.append(row_data)
        return table_data


class DateInputDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle("Date Filter")
        layout = QVBoxLayout(self)

        self.date_edit = QDateTimeEdit(self)
        self.date_edit.setDisplayFormat("yyyy-MM-dd")

        layout.addWidget(self.date_edit)

        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

        layout.addWidget(buttons)

    def get_date(self):
        return self.date_edit.date()


class SignatureDialogIssued(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Signature Issued By")

        self.layout = QVBoxLayout()

        self.signature_label = QLabel("Please draw your signature:")
        self.signature_widget = SignatureWidget(self)

        self.ok_button = QPushButton("OK")
        self.cancel_button = QPushButton("Cancel")

        self.ok_button.clicked.connect(self.accept)
        self.cancel_button.clicked.connect(self.reject)

        self.layout.addWidget(self.signature_label)
        self.layout.addWidget(self.signature_widget)
        self.layout.addWidget(self.ok_button)
        self.layout.addWidget(self.cancel_button)

        self.setLayout(self.layout)

    def get_signature(self):
        return self.signature_widget.get_signatureissued()

class SignatureDialogReceived(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("Signature (Received By)")

        self.layout = QVBoxLayout()

        self.signature_label = QLabel("Please draw your signature:")
        self.signature_widget = SignatureWidget(self)

        self.ok_button = QPushButton("OK")
        self.cancel_button = QPushButton("Cancel")

        self.ok_button.clicked.connect(self.accept)
        self.cancel_button.clicked.connect(self.reject)

        self.layout.addWidget(self.signature_label)
        self.layout.addWidget(self.signature_widget)
        self.layout.addWidget(self.ok_button)
        self.layout.addWidget(self.cancel_button)

        self.setLayout(self.layout)

    def get_signature(self):
        return self.signature_widget.get_signaturerecieved()

class SignatureWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedSize(300, 100)
        self.path = QPainterPath()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.drawPath(self.path)

    def mousePressEvent(self, event):
        self.path.moveTo(event.pos())

    def mouseMoveEvent(self, event):
        self.path.lineTo(event.pos())
        self.update()

    def get_signatureissued(self):
        image = QImage(self.size(), QImage.Format_ARGB32)
        image.fill(Qt.white)
        painter = QPainter(image)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.drawPath(self.path)
        painter.end()
        image.save("signatureissued.png")



        return "signatureissued.png"
    def get_signaturerecieved(self):
        image = QImage(self.size(), QImage.Format_ARGB32)
        image.fill(Qt.white)
        painter = QPainter(image)
        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.drawPath(self.path)
        painter.end()
        image.save("signaturerecieved.png")

        return "signaturerecieved.png"


if __name__ == "__main__":
    # app = QApplication(sys.argv)
    window = EmployeeDetailsApp()
    window.show()
    sys.exit(app.exec_())
  • I want the ADD button to stay hidden even if I add new rows to the table.

Some info abt the code :slight_smile:

  1. Table is created in “create_table” function

  2. ADD button in the table is created in “create_button_widgetissued” and “create_button_widgetrecieved” function

  3. New rows and buttons are added to the table in “enter_details” function

  4. Signature dialog box is opened in “open_signature_dialog_issued” and open_signature_dialog_recieved" function. (it uses SignatureDialog class in the botttom of the code)

  5. “hiderec” and “hideiss” functions hide the ADD buttons in the table.

  6. Visibility status of buttons is stored in “button_widgets” list.

I’ve literally tried eveything. Googled it, used CHATGPT, nothing seems to work.



Hey @Joker this is pretty strange. I’ve played around with the code a bit & confirm (a) that it’s happening, and (b) that it is the same widgets that are being re-shown (by adding a number to the specific widget when it’s added).

By creating a custom QWidget class I can confirm that the widget’s .show() method isn’t actually being called. So what I suspect is happening is that the widget is being re-added to a layout on refresh & this is what’s triggering the visibility.

But either way, there’s a simple solution: you have a push button nested inside the widget. If you call .hide() on the push button this won’t be reshown. Since you’re passing out the widget reference, you need to make the button available on it, so, e.g.

    def create_button_widgetissued(self, row, col):
        button_widget = CustomWidget(self)
        layout = QVBoxLayout(button_widget)

        add_button = QPushButton("Add", button_widget)
        add_button.clicked.connect(lambda _, r=row: self.open_signature_dialog_issued(r))

        layout.addWidget(add_button)
        layout.setAlignment(add_button, Qt.AlignCenter)
        button_widget.add_button = add_button # keep a ref on the container widget
        return button_widget

Then the hide would become

    def hideiss(self, row):
        self.button_widgets[row]["issued"].add_button.hide()

Hope that helps.