Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > ошибка в редакторе при работе в делегате


Автор: olegkuzn 16.11.2015, 09:47
Здраствуйте знатоки Qt.

Помогите избавиться от ошибки.
При работе собственного редактора после вызова стандартного диалога открытия файла
необходимо записать значение полученное в в собственный виджет. Однако происходит аварийное
завершение программы. 

Выкладываю код. В комментариях постарался все подробно описать.

Код моего виджета
1. lineedit.h
Код

#ifndef LINEEDIT
#define LINEEDIT
#include <QLineEdit>
#include <QStyleOptionButton>

// создаем свой виджет "строка с кнопкой" на основе стандартного QLineEdit
// который будет использоваться как редактор в нашем делегате (class MyDelegate)
class LineEdit : public QLineEdit
{
    Q_OBJECT

public:
    LineEdit(QWidget* parent = 0);

private:
    int m_nRightMargin; // отступ от правого края для "кнопки"
    QStyleOptionButton m_optButton; // стиль кнопки

protected:
    // перегруженные ф-ции обработки событий
    virtual void paintEvent(QPaintEvent* event);
    virtual void mousePressEvent(QMouseEvent *);
    virtual void mouseReleaseEvent(QMouseEvent*);
};

#endif // LINEEDIT

2. lineedit.cpp
Код


#include "lineedit.h"
#include <QPainter>
#include <QApplication>
#include <QStyle>
#include <QMouseEvent>
#include <QFileDialog>

// конструктор
LineEdit::LineEdit(QWidget *parent)
        : QLineEdit(parent)
{
    m_nRightMargin = 20;
    setTextMargins(0,0,m_nRightMargin,0);
    setReadOnly(true);

    // определяем стиль и текст нашей "кнопки"
    m_optButton.text = "...";
    m_optButton.features = QStyleOptionButton::DefaultButton;
    m_optButton.state |= (QStyle::State_Raised | QStyle::State_Enabled );

}

void LineEdit::paintEvent(QPaintEvent *event)
{
    // отрабатываем стандарный paintEvent
    QLineEdit::paintEvent(event);

    QPainter painter(this);

    // определяем размеры "кнопки" на нашем виджете
    QRect rectBtn = event->rect();
    rectBtn.setLeft(rectBtn.width()-rectBtn.height());
    m_optButton.rect = rectBtn;

    // прорисовываем кнопку
    QApplication::style()->drawControl(QStyle::CE_PushButton,&m_optButton, &painter);
}

void LineEdit::mousePressEvent(QMouseEvent* event)
{
    // отрабатываем стандарный mousePressEvent
    QLineEdit::mousePressEvent(event);

    // если нажатие мыши произошло на месте кнопки нашего виджета
    if(m_optButton.rect.contains(event->pos()))
    {

        // изменяем состояние кнопки на нажатое и прорисовываем ее
        m_optButton.state |= QStyle::State_Sunken;
        update();

        // вызываем стандартный диалог открытия файла
        QString strFileName = QFileDialog::getOpenFileName( 0, QString("Журнал сканеров"), QDir::currentPath(),QString("любой файл, *.*"),0);

        // и если файл выбран то в св-во текст занести путь к файлу
        if(!strFileName.isEmpty())
            setText(strFileName);   // ВОТ ЗДЕСЬ И ПРОИСХОДИТ ОШИБКА
                                    // у меня создалось впечатление что при вызове
                                    // стандартного диалога редактор в делегате удаляется.
                                    // Подскажите как избежать такого поведения
    }
}

void LineEdit::mouseReleaseEvent(QMouseEvent *event)
{
    // отрабатываем стандарный mouseReleaseEvent
    QLineEdit::mouseReleaseEvent(event);

    // если отжатие мыши произошло на месте кнопки нашего виджета
    if(m_optButton.rect.contains(event->pos()))
    {
        // возвращаем "кнопку" в первоначальное состояние и прорисовываем виджет
        m_optButton.state &= !(QStyle::State_Sunken);
        m_optButton.state |= (QStyle::State_Raised | QStyle::State_Enabled );
        update();
    }
}



Заодно выкладываю реализацию своего делегата для класса QTableView
mydelegate.h
Код

#include "mydelegate.h"
#include <QPainter>
#include <QApplication>
#include <QPushButton>
#include <QFileDialog>
#include "lineedit.h"

QWidget* MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
   Q_UNUSED(option)
   Q_UNUSED(index )

   LineEdit* label = new LineEdit(parent);
   label->setText(index.data().toString());
   return label;
}

void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    LineEdit* lineEdit = (LineEdit*)editor;
    lineEdit->setText(index.data().toString());
}

void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    LineEdit* lineEdit = (LineEdit*)editor;
    QString str = lineEdit->text();
    model->setData(index, QVariant(str));
}


Автор: math64 16.11.2015, 14:04
Я бы реализовал редактор так (у Вас редактор будет отображаться неправильно при длинном имени файла):
Код

class LineEdit : public QWidget
{
    Q_OBJECT

public:
    LineEdit(QWidget* parent = 0);
    ~LineEdit() { QDebug() << "~LineEdit"; } // Ловим момент когда редактор удаляется
    QLineEdit* editor() { return edit; }
private:
    QLineEdit* edit;
    QPushButton* button;
    QHBoxLayout* layout;

private slots:
    void onButtonClicked();
};

Если редактор действительно удаляется - будет вызван деструктор.

Автор: olegkuzn 16.11.2015, 22:50
math64 Спасибо большое за предложенный вариант.
Я примерно так и реализовал редактор для делегата.
Все вроде бы работает.

Добавлено через 51 секунду
math64 Спасибо большое за предложенный вариант.
Я примерно так и реализовал редактор для делегата.
Все вроде бы работает.

Автор: olegkuzn 16.11.2015, 23:05
math64 Спасибо большое за предложенный вариант.
Я примерно так и реализовал редактор для делегата.
Все вроде бы работает.

Добавлено через 28 секунд
math64 Спасибо большое за предложенный вариант.
Я примерно так и реализовал редактор для делегата.
Все вроде бы работает.

Автор: math64 17.11.2015, 08:07
В Вашем первоначальном варианте, скорее всего, в mousePressEvent() нужно было бы установить флажок,
в mouseReleaseEvent() проверить этот флажок и emit'ить сигнал, а диалог вызывать в слоте.
Но я не уверен.
Кроме того, советую в делегате реализовать метод:
Код

class MyDelegate : public QStyledItemDelegate
{
    ...
    virtual QString displayText(const QVariant &value, const QLocale &locale) const;
    // или этот:
    virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

и при длинном имени файла сокращать имена каталогов - по умолчанию будет обрезан конец строки.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)