QDateEdit всплывающее окно календаря

Я пытаюсь получить QDateEdit чтобы позволить QCalendarWidget показывать при запросе (а не просто при нажатии на стрелку вниз). Например, где-то в моем классе я мог бы сказать:

ui.datepicker.showCalendar()

и это должно загрузить календарь, который появляется прямо ниже выбора даты.

Похоже, мне нужно подкласс QDateEdit, поскольку это не работает:

QDateEdit *de = new QDateEdit();
de->calendarWidget()->show();

Я также пытался посылать команды клавиатуры, как предписано, когда вы просматриваете исходный код QDateTimeEdit.cpp для Qt, но, кажется, мои сочетания клавиш отключены или что-то в этом роде.

Любые идеи о том, что я должен сделать для подкласса, чтобы заставить это работать? Я думал о чем-то вроде:

class MyDateEdit : QDateEdit
{
  Q_OBJECT

protected:
  void mouseEvent(QEvent *event) {
    this.calendarWidget().show();
  }
};

Но, увы, похоже, что он не компилируется или работает неправильно.

3 ответа

Решение

Я смог понять это самостоятельно - все еще не уверен, как заставить QDateEdit работать должным образом, но я использовал QLineEdit, и он соответствовал моим потребностям. Просто подключите QCalendarWidget "onClick(QDate)" к слоту, который вы создаете, который делает:

setText(date.toString("M/d/yyyy"));
ui->calendar->hide();

Затем добавьте фильтр событий в QLineEdit, используя событие "OnFocusIn", которое выполняет "ui->calendar->show();" Смотрите: Получить уведомление / событие / сигнал, когда виджет Qt получает фокус

Включить "setCalendarPopup ( bool enable)" в QDateTimeEdit позволяет всплывающий календарь

@Rob S ответ

Вы были правы с подходом фильтра событий, мы сделали бы то же самое с QDateEdit.

Я пишу код, который расширяет ваш подход с QDateEdit:

В mainwindow.h я создал указатель QCalendar (используя QtCreator)

Ниже приведен код mainwindow.cpp (я выдаю полный код, чтобы новички, такие как я, могли получить от него выгоду)

Убедитесь, что для свойства buttonSymbol и calendarpopup установлено значение false, чтобы оно работало правильно

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCalendarWidget>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->dateEdit->setDate(QDate::currentDate());

    widget=new QCalendarWidget(); //widget is QCalendar pointer

    ui->verticalLayout->addWidget(widget);
    widget->setWindowFlags(Qt::Popup); // we need widget to popup 

    ui->dateEdit->installEventFilter(this);
    connect(widget,SIGNAL(clicked(QDate)),ui->dateEdit,SLOT(setDate(QDate)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::InputMethodQuery)
    {
        if (object == ui->dateEdit)
        {

          if(widget->isVisible()==false && ui->dateEdit->calendarWidget()->isVisible()==false) // this done to avoid conflict
          {
                qWarning(QString().number(event->type()).toStdString().c_str());
                qWarning(object->objectName().toLatin1().data());
                widget->move(ui->dateEdit->mapToGlobal(QPoint(0,ui->dateEdit->height())));
                widget->show();
          }

        }

    }
    return false;
}

ИЛИ:: В качестве альтернативы мы можем использовать QCalendarWidget, предоставляемый dateEdit, хотя это не очень эффективно, так как включение его в Popup будет портить его внутреннее. Дайте ему шанс, если хотите

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCompleter>
#include <QCalendarWidget>
#include <QMouseEvent>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->dateEdit->setDate(QDate::currentDate());

    widget = ui->dateEdit->calendarWidget();
    widget->setWindowFlags(Qt::Popup);

    ui->dateEdit->installEventFilter(this);

    //connecting widget with dateedit
    ui->dateEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
    ui->dateEdit->setCalendarPopup(true);

    connect(widget,SIGNAL(clicked(QDate)),ui->dateEdit,SLOT(setDate(QDate)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
    if (object == ui->dateEdit)
    {
        if (event->type() == QEvent::FocusIn || event->type() == QEvent::MouseButtonPress)
        {    
           // WE NEED MOUSE EVENT TO AVOID INTERFERNCE WITH CALENDAR POPUP BUTTON SITUATED AT CORNER OF dateEdit WIDGET
            if(widget->isVisible()==false && ( ((QMouseEvent* )event)->x()< (ui->dateEdit->width()-10)))
            {
                widget->move(ui->dateEdit->mapToGlobal(QPoint(0,ui->dateEdit->height())));
                widget->show();
            }
        }    
    }
    return false;
}

Хочу предложить вариант, аналогичный @Dr. Ответ Xperience, который инкапсулирует виджет календаря в подклассе QDateEdit:

#include <QDateEdit>
#include <QCalendarWidget>

class DateEdit : public QDateEdit {
    Q_OBJECT

public:
    explicit DateEdit(QWidget *parent = nullptr);

protected:
    virtual void focusInEvent(QFocusEvent *event) override;

private:
    QCalendarWidget *calendar = new QCalendarWidget(this);
};

DateEdit::DateEdit(QWidget *parent) : QDateEdit (parent) {
    setButtonSymbols(QAbstractSpinBox::NoButtons);
    setCalendarPopup(false);
    setDate(QDate::currentDate());

    calendar->setWindowFlags(Qt::Popup);
    connect(calendar, &QCalendarWidget::clicked, this, [&](const QDate &date) {
        setDate(date);
        calendar->hide();
    });
}

void DateEdit::focusInEvent(QFocusEvent *event) {
    if (!calendar->isVisible()) {
        calendar->setSelectedDate(date());
        calendar->move(mapToGlobal(QPoint(0, height())));
        calendar->show();
    }

    return QDateEdit::focusInEvent(event);
}

Предупреждение: если вы разместите этот виджет с помощью QtDesigner, он переопределит свойства buttonSymbols и calendarPopup, поэтому вы должны установить его вручную, чтобы скрыть кнопки QDateEdit.

Вот мой хакерский подход к проблеме. После долгой борьбы за что-то чистое, я прочитал исходный кодQDateEditor (что на самом деле просто упрощенное QDateTimeEditor) и, похоже, это не чистое решение. Ниже приведен код дляtoggle() скорее, чем show(), но до сих пор:

// Enable the calendar popup
date_editor->setCalendarPopup(true);

// Show the calendar popup by default
// There seems to be no proper interface to achieve that
// Fake a mouse click on the right-hand-side button
QPointF point = date_editor->rect().bottomRight() - QPointF{5, 5};
QCoreApplication::postEvent(
    date_editor,
    new QMouseEvent(QEvent::MouseButtonPress, point, Qt::LeftButton,
                    Qt::LeftButton, Qt::NoModifier));

Используя что-то вроде этого, вы можете продолжать полагаться на функции проверки редактора.

Кстати, еще одна неприятная вещь о встроенном редакторе, который делает QLineEditЗаманчиво то, что (по крайней мере, в моем случае) курсор клавиатуры по умолчанию не отображается. Это очень сбивает с толку. Чтобы решить эту проблему, я сделал:

// Select a section so that the cursor is be visible
date_editor->setSelectedSection(QDateTimeEdit::DaySection);

Это или, конечно, выбирает дневную часть даты, но если вы используете стрелки на клавиатуре, выделение исчезнет, ​​но вы можете увидеть курсор на клавиатуре.

Другие вопросы по тегам