Ich implementierte eine Einheit Textfeld, die Konvertierungen vornehmen kann, wenn eine andere Einheit ausgewählt ist. Dies wurde getan, indem QLineEdit und QLabel mit einem QHBoxLayout zusammengefügt wurden.Qt Delegate Anzeige Text gerendert, während Editor aktiv ist
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);
}
Als nächstes abgeleitet ich eine QStyledItemDelegate so, dass ich in dieses Textfeld in meinem eigenen QTableView nutzen könnte.
Wenn Sie sehr genau hinsehen, werden Sie sehen, dass der Buchstabe "m" hinter dem Hyperlink "m" angezeigt wird, wenn der Editor für diesen Delegaten aktiv ist.
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);
}
Bis jetzt ist die einzige Lösung, die ich gefunden habe, die Hintergrundfarbe auf meinem Editor Widget zu setzen. Das fühlt sich hackisch an, da muss etwas anderes passieren, was ich falsch mache.
Gibt es eine Möglichkeit, die Qt :: DisplayRole Text, um zu verhindern gemacht wird, während mein Editor aktiv ist?
Welche Klasse ist eigentlich 'LengthTextBox' abgeleitet aus? – Tomas
Ich habe meinen Beitrag bearbeitet, er stammt von QWidget – ASxa86