2016-12-06 22 views
0

我實現了一個單位文本框,在選擇了其他單位時可以進行轉換。這是通過使用QHBoxLayout將QLineEdit和QLabel粘在一起來完成的。編輯器處於活動狀態時呈現Qt代表顯示文本

enter image description here

class LengthTextBox::Impl 
{ 
    public: 
     Impl() : 
      lblUnit(new QLabel()), 
      txtValue(new QLineEdit()), 
      menuLength(new LengthMenu(lblUnit)), 
      precision(2), 
      unit(units::Length::Meters) 
     { 
     } 

     QLabel* lblUnit; 
     QLineEdit* txtValue; 
     LengthMenu* menuLength; 

     int precision; 

     units::Length unit; 
}; 

LengthTextBox::LengthTextBox(QWidget* parent) : QWidget(parent), 
    pimpl() 
{ 
    const auto hLayout = new QHBoxLayout(this); 

    // Adjust spacing for better fit within tables. 
    const auto spacing = 2; 
    auto margins = hLayout->contentsMargins(); 
    margins.setTop(0); 
    margins.setLeft(spacing); 
    margins.setRight(spacing); 
    margins.setBottom(0); 
    hLayout->setContentsMargins(margins); 
    hLayout->setSpacing(spacing); 

    this->pimpl->txtValue->setValidator(new QDoubleValidator()); 

    // Install an event filter to capture focus out events. 
    this->pimpl->txtValue->installEventFilter(this); 

    hLayout->addWidget(this->pimpl->txtValue); 
    hLayout->addWidget(this->pimpl->lblUnit); 

    // Since we're building on top of a QWidget, set up the focus policies to still focus on the text box. 
    this->setFocusProxy(this->pimpl->txtValue); 
    this->pimpl->txtValue->setFocusPolicy(Qt::StrongFocus); 
    this->pimpl->lblUnit->setFocusPolicy(Qt::ClickFocus); 

    // Connect signals for switching between units. 
    this->connect(this->pimpl->lblUnit, &QLabel::linkActivated, this, &LengthTextBox::unitSelectorClicked); 
    this->connect(this->pimpl->menuLength, &LengthMenu::unitChanged, this, &LengthTextBox::setUnit); 

    // Forward the line edit signals. 
    this->connect(this->pimpl->txtValue, &QLineEdit::editingFinished, this, &LengthTextBox::editingFinished); 
    this->connect(this->pimpl->txtValue, &QLineEdit::returnPressed, this, &LengthTextBox::returnPressed); 
    this->connect(this->pimpl->txtValue, &QLineEdit::textChanged, this, &LengthTextBox::textChanged); 
    this->connect(this->pimpl->txtValue, &QLineEdit::textEdited, this, &LengthTextBox::textEdited); 

    this->setUnit(this->pimpl->unit); 
} 

LengthTextBox::~LengthTextBox() 
{ 
} 

void LengthTextBox::setPrecision(int x) 
{ 
    this->pimpl->precision = x; 
} 

int LengthTextBox::getPrecision() const 
{ 
    return this->pimpl->precision; 
} 

void LengthTextBox::setUnit(const units::Length& x) 
{ 
    const auto value = this->getValue(); 
    this->setValue(units::Convert(value, this->pimpl->unit, x)); 

    // Use HTML to render the text as a link. This will lead to the linkActivated signal when clicked. 
    const QString link = "<b><a href='#'>" + QString::fromStdString(units::GetSymbol(x)) + "</a></b>"; 
    this->pimpl->lblUnit->setText(link); 

    this->pimpl->txtValue->setFocus(Qt::FocusReason::OtherFocusReason); 
    this->pimpl->txtValue->selectAll(); 

    this->pimpl->unit = x; 
    this->unitChanged(this->pimpl->unit); 
} 

units::Length LengthTextBox::getUnit() const 
{ 
    return this->pimpl->unit; 
} 

void LengthTextBox::setValue(double x, const units::Length& fromUnit) 
{ 
    if(fromUnit != units::Length::Unknown) 
    { 
     x = units::Convert(x, fromUnit, this->pimpl->unit); 
    } 

    this->pimpl->txtValue->setText(QString::number(x, 'f', this->pimpl->precision)); 
} 

double LengthTextBox::getValue(const units::Length& toUnit) const 
{ 
    auto value = this->pimpl->txtValue->text().toDouble(); 

    if(toUnit != units::Length::Unknown) 
    { 
     value = units::Convert(value, this->pimpl->unit, toUnit); 
    } 

    return value; 
} 

std::string LengthTextBox::getFormattedText() const 
{ 
    return this->pimpl->txtValue->text().toStdString() + " " + units::GetSymbol(this->pimpl->unit); 
} 

void LengthTextBox::unitSelectorClicked() 
{ 
    this->pimpl->menuLength->popup(QCursor::pos()); 
} 

bool LengthTextBox::eventFilter(QObject* obj, QEvent* x) 
{ 
    // Watch for a focus out event on the text box inorder to send a lost focus signal. 
    if(this->pimpl->txtValue == obj) 
    { 
     if(x->type() == QEvent::FocusOut && this->pimpl->lblUnit->hasFocus() == false) 
     { 
      this->lostFocus(); 
      return true; 
     } 
    } 

    return QWidget::eventFilter(obj, x); 
} 

接下來,我得出的QStyledItemDelegate,這樣我可以在我自己的QTableView中使用該文本框。 enter image description here

如果您看起來非常密切,您會看到當編輯器在此代理上處於活動狀態時,字母'm'會顯示在超鏈接'm'的後面。

class LengthTextBoxDelegate::Impl 
{ 
    public: 
     Impl(int precision) : 
      txtLength(std::make_unique<LengthTextBox>()) 
     { 
      this->txtLength->setPrecision(precision); 
     } 

     // By using a length text box to manage current selected unit, all conversion logic remains in one place. 
     std::unique_ptr<LengthTextBox> txtLength; 
}; 

LengthTextBoxDelegate::LengthTextBoxDelegate(int precision, QWidget* parent) : QStyledItemDelegate(parent), 
    pimpl(precision) 
{ 
} 

LengthTextBoxDelegate::~LengthTextBoxDelegate() 
{ 
} 

QString LengthTextBoxDelegate::displayText(const QVariant& value, const QLocale&) const 
{ 
    this->pimpl->txtLength->setValue(value.toDouble(), Length::Meters); 
    return QString::fromStdString(this->pimpl->txtLength->getText()) + " " + QString::fromStdString(GetSymbol(this->pimpl->txtLength->getSelectedUnit())); 
} 

QWidget* LengthTextBoxDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const 
{ 
    const auto txtLength = new LengthTextBox(parent); 
    txtLength->setValue(index.data().toDouble()); 
    txtLength->setSelectedUnit(this->pimpl->txtLength->getSelectedUnit()); 
    txtLength->setPrecision(this->pimpl->txtLength->getPrecision()); 

    // AMS // This is kind of a hack. For some reason, the ::displayText() that is rendered when no editor is created, was getting rendered 
    // behind the editor widget and was appearing through as if the text box was transparent. 
    // By setting the background color white, we get a nice aesthetic that matches the table views that use this delegate. 
    // In addition, it covers up the text that was appearing behind the widget. 
    auto p = txtLength->palette(); 
    p.setColor(QPalette::Base, Qt::white); 
    txtLength->setPalette(p); 
    //txtLength->setAutoFillBackground(true); 

    // Track the current unit so that its symbol can be rendered when ::displayText() is called. 
    this->connect(txtLength, &LengthTextBox::unitChanged, this, &LengthTextBoxDelegate::unitChanged); 
    this->connect(txtLength, &LengthTextBox::returnPressed, this, &LengthTextBoxDelegate::commitAndCloseEditor); 
    this->connect(txtLength, &LengthTextBox::lostFocus, this, &LengthTextBoxDelegate::commitAndCloseEditor); 

    return txtLength; 
} 

void LengthTextBoxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const 
{ 
    const auto txtLength = qobject_cast<LengthTextBox*>(editor); 
    assert(txtLength != nullptr); 

    txtLength->setValue(index.data().toDouble(), Length::Meters); 
} 

void LengthTextBoxDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const 
{ 
    const auto txtLength = qobject_cast<LengthTextBox*>(editor); 
    assert(txtLength != nullptr); 

    model->setData(index, txtLength->getValue(Length::Meters)); 
} 

void LengthTextBoxDelegate::unitChanged(const hive::math::units::Length& x) 
{ 
    this->pimpl->txtLength->setSelectedUnit(x); 
} 

void LengthTextBoxDelegate::commitAndCloseEditor() 
{ 
    const auto txtLength = qobject_cast<LengthTextBox*>(this->sender()); 
    this->commitData(txtLength); 
    this->closeEditor(txtLength); 
} 

到目前爲止,我想出的唯一辦法是設置在我的編輯器插件的背景顏色。這感覺很ha,,還有一些我做錯的事情。

enter image description here

有沒有一種方法,以防止被渲染,而我的編輯器激活了Qt :: DisplayRole文本?

+0

實際上是'LengthTextBox'源自什麼課? – Tomas

+0

我編輯了我的帖子,它來自QWidget – ASxa86

回答

2

您需要在繪製編輯器小部件之前填充背景。 QWidgetautoFillBackground屬性控制此行爲,因爲默認情況下它被設置爲false,您的編輯器小部件將被繪製在QTableView上。

你只需要返回之前設置在編輯器中的財產createEditor()

txtLength->setAutoFillBackground(true); 

背景的顏色使用setBackgroundRole(),在默認情況下繼承了父母的背景指定(即QPalette::Base如果父母是QTableView)。所以,你會得到的白色背景的編輯器,你可能要改爲指定QPalette::Window顏色角色:

txtLength->setBackgroundRole(QPalette::Window); 
相關問題