Search code examples
pythonpython-3.xpyqt5qcalendarwidget

How to transfer date selection from calendar widget to QLineEdit


I'm playing around with PyQt5 (which I just started learning yesterday).

I'm trying to create a window/layout, with two entry boxes (to enter 'start' and 'end' dates), so that when each one is clicked, the QCalendarWidget is triggered to popup, and when the user selects the date, the date is entered into the QLineEdit field.

So far, it simply shows a blank window, but I'm not sure what I'm doing wrong.

class selectedDate(QWidget):
    def __init__(self):
        super(selectedDate, self).__init__()
        self.layout = QVBoxLayout(self)
        self.selection = QLineEdit("Click to Enter Date", self)
        self.layout.addWidget(self.selection)
        self.layout.addWidget(self.selection)
        self.selection.installEventFilter(self)


    def mousePressEvent(self, e):
        self.myCal()
        super(selectedDate, self).mousePressEvent(e)

    def eventFilter(self, object, e):
        if self.layout.indexOf(object) != -1:
            if e.type() == e.MouseButtonPress:
                pass

        return super(selectedDate, self).eventFilter(object, e)



    def myCal(self):
        self.cal = QCalendarWidget(self)
        self.cal.setGridVisible(True)
        self.cal.move(10, 20)
        self.cal.clicked[QDate].connect(self.showDate)

        self.date = self.cal.selectedDate()
        self.selection.setText(self.date.toString())

        self.setGeometry(300, 300, 415, 350)
        self.setWindowTitle('Calendar')
        self.show()

    def showDate(self, date):
        self.selection.setText(date.toString())

app = QApplication(sys.argv)
top = selectedDate()
app.exec_()

Solution

  • There's quite a lot of issues, let's work through some.

    To see a window, you need to call QWidget.show(). Here you only call self.show() in myCal method. But myCal is only called with a mouse click. Surely you want to display the window right after starting the application. To do that you can simply put self.show() at the end of the __init__ method.

    class SelectedDate(QWidget):
        def __init__(self):
            # layout stuff, QLineEdit, etc
            self.show() # show your first window with the QLineEdit
    

    Next, the mouse press event. The method mousePressEvent is actually never called! You can check that by adding a print statement in it. It should be called when a MouseButtonPress is detected (in eventFilter)


    Finally the calendar widget. We want to open it in a new window (QCalendarWidget doesn't open as a pop up by default, you need to do it yourself).

    def myCal(self):
        self.cal = QCalendarWidget(self)
        self.cal.setGridVisible(True)
        self.cal.clicked[QDate].connect(self.showDate)
    
        # create a new window that contains the calendar
        self.calendarWindow = QWidget()
        hbox = QHBoxLayout()
        hbox.addWidget(self.cal)
        self.calendarWindow.setLayout(hbox)
        self.calendarWindow.setGeometry(300, 300, 415, 350)
        self.calendarWindow.setWindowTitle('Calendar')
        # open this new window
        self.calendarWindow.show()
    

    Now some more advice. You should start by a simple app and build more functionality when it works. Writing a lot of code for only a blank window it not a good idea! So if you where to do this again, work by steps:

    • Show a window with a QLineEdit (write code, test that it works)
    • Implement the event filter (use print statements to see if it works)
    • Implement opening a new blank window when clicking the QLineEdit
    • Fill that blank window with the calendar
    • Connect the calendar to the QLineEdit text (that code was good by the way)

    Also, you can use better variable names, some suggestions:

    • selectedDate -> SelectDateWidget
    • selection -> date_selection
    • mousePressEvent -> on_date_selection_clicked
    • myCal -> open_calendar
    • cal -> calendar
    • showDate -> on_calendar_clicked or update_date_selection_text