PDA

View Full Version : Editable QLCDNumber



QDmitry
25th June 2013, 17:22
Hi guys

I'd like to hear you suggestions to the following problem.

I need an editable lcd editor in my GUI. I mean that I display some value in it and allow a user to edit it in a clickable way. For example, the current value is 123. A user clicks to the area of digit 2 and press some digit key on his keyboard to modify this digit.

The quick solution spinning in my mind is to implement a QButton over the QLCDNumber widget but it seems to be a dirty hack.

Are there any tested solutions for this case? If anyone could share an example I'd be highly appreciated. But anyhow I need a concept to start.

My environment : Qt4.7, no QML.

BR,
Dmitry

wysota
25th June 2013, 18:00
Subclass QLCDNumber, activate focus and reimplement key events.

QDmitry
26th June 2013, 15:42
Thx for the idea.
Could you please clarify the following items:
1. "activate focus" - do you mean setFocus() method?
2. "reimplement key events" -ok, this is quite clear. But how do I know the exact item position to be edited? I guess I should somehow track the mouse position and the desired digit position of the LCD, right? If yes, then what is the way to get the LCD item position?

Added after 1 20 minutes:

and
3. What is the right wat to highlight the "editable" item of the current LCD value?
Inside Qt help I see the following note : "It is not possible to retrieve the contents of a QLCDNumber object, although you can retrieve the numeric value with value()". Therefore my question : is it possible to find a solution based on QLCDNumber?

QDmitry
27th June 2013, 15:57
Ok, so here is my solution to this topic.
==============================
qeditablelcd.h
==============================
#ifndef QEDITABLELCD_H
#define QEDITABLELCD_H

#include <QLCDNumber>
#include <QPaintEvent>
#include <QKeyEvent>
#include <QRectF>
#include <QWheelEvent>

class qeditablelcd : public QLCDNumber
{
Q_OBJECT
public:
explicit qeditablelcd(QObject *parent = 0);

signals:

public slots:

protected :
void mousePressEvent ( QMouseEvent * e );
void keyPressEvent ( QKeyEvent * event );
void paintEvent( QPaintEvent * e );
void wheelEvent ( QWheelEvent * event );

private :
void setDigitAreaPressed( QMouseEvent * e, const int areaId = -1 );
void positionValueIncrement( const int numSteps );
QRectF mDigitRect;
int mDigitIdToChange;
};

#endif // QEDITABLELCD_H

======================
qeditablelcd.cpp
======================
#include <QMouseEvent>
#include <QBrush>
#include <QPainter>
#include <QString>
#include <QtCore/qmath.h>

#include "qeditablelcd.h"

qeditablelcd::qeditablelcd(QObject *parent) :
QLCDNumber()
{
/* Mouse selected digit item Id */
this->mDigitIdToChange = -1;
this->setFocusPolicy(Qt::ClickFocus);
}

void qeditablelcd::setDigitAreaPressed( QMouseEvent * e, const int areaId )
{
int ndigits = this->digitCount();
int digitSpace = this->smallDecimalPoint() ? 2 : 1;
int xSegLen = this->width()*5/(ndigits*(5 + digitSpace) + digitSpace);
int ySegLen = this->height()*5/12;
int segLen = ySegLen > xSegLen ? xSegLen : ySegLen;
int xAdvance = segLen*( 5 + digitSpace )/5;
int xOffset = ( this->width() - ndigits*xAdvance + segLen/5 )/2;

/* Use the predefined Id if necessary */
if ( areaId != -1 ) {
this->mDigitRect.setRect(xOffset + xAdvance*areaId, this->y(), xAdvance, this->height() );
return;
}

int xPos = e->pos().x();
int itemId = -1;

for ( int i = 0; i < ndigits; i++ ) {
if ((xPos >= xOffset + xAdvance*i) && (xPos < xOffset + xAdvance*(i + 1))) {
itemId = i;
this->mDigitRect.setRect(xOffset + xAdvance*itemId, this->y(), xAdvance, this->height() );
break;
}
}

this->mDigitIdToChange = itemId;
}

void qeditablelcd::mousePressEvent ( QMouseEvent * e )
{
this->setDigitAreaPressed(e);
update();
}

void qeditablelcd::paintEvent(QPaintEvent * e)
{
/* If are not selected - nothing to draw except lcdnumber itself */
/* Though never occured while testing */
if (!( this->mDigitIdToChange == -1 )) {
QPainter Painter(this);
Painter.setBrush(QBrush(Qt::black, Qt::Dense7Pattern));
Painter.drawRect(this->mDigitRect);
}
QLCDNumber::paintEvent(e);
}

void qeditablelcd::keyPressEvent ( QKeyEvent * event )
{
int key = event->key();

/* Filter out all non digit keys */
if (( key >= Qt::Key_0 ) && ( key <= Qt::Key_9 )) {
if ( this->mDigitIdToChange != -1 ) {
/* Convert double value to a string representation */
QString lcdStr;
lcdStr.setNum(int(this->value()));

/* Insert starting zeros in lcdStr representation */
int l = this->digitCount() - lcdStr.length();
for (int i = 0; i < l; i++) {
lcdStr.insert(0,"0");
}

/* Convert key value to string representation */
QString keyVal;
keyVal.setNum( key - Qt::Key_0 );

/* Replace selected digit with the desired one */
lcdStr.replace(this->mDigitIdToChange, 1, keyVal);

/* Update lcdnumber */
this->display(lcdStr.toDouble());

/* Switch to the next digit item */
if ( this->mDigitIdToChange == this->digitCount() - 1 ) {
this->mDigitIdToChange = 0;
} else {
this->mDigitIdToChange++;
}

this->setDigitAreaPressed(NULL, this->mDigitIdToChange);
update();
}
}

/* Enter + Esc press event handler */
if (( key == Qt::Key_Return ) || ( key == Qt::Key_Escape )) {
this->mDigitIdToChange = -1;
update();
}

}

void qeditablelcd::wheelEvent ( QWheelEvent * event )
{
if ( this->mDigitIdToChange != -1 ) {
/* Number of steps within a single event = delta() / (15*8) */
this->positionValueIncrement(event->delta()/(15*8));
}
}

void qeditablelcd::positionValueIncrement( const int numSteps )
{
/* Multiply rate */
qreal multiplyer = qPow( 10, this->digitCount() - 1 - this->mDigitIdToChange );

this->display(this->value() + numSteps*multiplyer );
}