Why IntValidator's bottom not working in QT? - qt

Now i am using a IntValidator in a TextInput with a bottom value greater than 0, just like:
validator: IntValidator{bottom: 20; top: 100;}
But i still can input a unwanted value like 10 and the input text won't clear after lose focus.
I don't know why? Anyone can help me.

IntValidator tries to validate your input every time you type a character and returns 3 possible states: Invalid, Intermediate, Acceptable.
Imagine a scenario where you set your bottom value to 20 and your top value to 1000.
Now you want to type 100, but the IntValidator would report Invalid for 1, 10 because these values are lower than 20, thus it would not let you enter any of these, this is why it returns Intermediate.
You can see what is going on in Qt's source:
QValidator::State QIntValidator::validate(QString & input, int&) const
{
QByteArray buff;
if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, -1,
locale().numberOptions())) {
return Invalid;
}
if (buff.isEmpty())
return Intermediate;
const bool startsWithMinus(buff[0] == '-');
if (b >= 0 && startsWithMinus)
return Invalid;
const bool startsWithPlus(buff[0] == '+');
if (t < 0 && startsWithPlus)
return Invalid;
if (buff.size() == 1 && (startsWithPlus || startsWithMinus))
return Intermediate;
bool ok;
qlonglong entered = QLocaleData::bytearrayToLongLong(buff.constData(), 10, &ok);
if (!ok)
return Invalid;
if (entered >= b && entered <= t) {
locale().toInt(input, &ok);
return ok ? Acceptable : Intermediate;
}
if (entered >= 0) {
// the -entered < b condition is necessary to allow people to type
// the minus last (e.g. for right-to-left languages)
// The buffLength > tLength condition validates values consisting
// of a number of digits equal to or less than the max value as intermediate.
int buffLength = buff.size();
if (startsWithPlus)
buffLength--;
const int tLength = t != 0 ? static_cast<int>(std::log10(qAbs(t))) + 1 : 1;
return (entered > t && -entered < b && buffLength > tLength) ? Invalid : Intermediate;
} else {
return (entered < b) ? Invalid : Intermediate;
}
}
If you want to reach your goal validating an integer within a range, better to let the user type anything except alphabetical and special characters (-+ should be allowed as first char) using a RegExpValidator and subscribe to the editingFinished and activeFocusChanged signals so when the user pressed enter or leaves the TextInput field you can validate the input value yourself and even update it to be in the desired range.

Related

Comparing two different pointers to elements of a linked list

Anyone knows if there are there any method for comparing the two pointers, let's say there are two pointers ptr1 and ptr2, as shown in the picture, how can i perform some operations similar (ptr2 < ptr1) to check whether a specific pointer passed another pointer, for example to check whether ptr2 passed ptr1 such that ptr2 is on the right side while ptr1 is on the left side. Thank you in advance.
Comparing the pointer values themselves will not tell you which node is before the other one in a linked list. For that you will need to step through your linked list.
You could have these pointers traverse the linked list in tandem. The one that reaches the end of the list first is necessarily the one that is coming after the other one.
In pseudo code (c-style):
int compare(node* ptr1, node* ptr2) {
if (ptr1 == ptr2) return 0; // equal
while (ptr1 != NULL && ptr2 != NULL) {
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}
return ptr2 == NULL ? -1 : 1;
}
If the list is long, and the pointers are not far from each other, you can gain some time by also checking whether one of the traversing pointers becomes equal to an original pointer. Then you can also take your conclusions:
int compare(node* ptr1, node* ptr2) {
if (ptr1 == ptr2) return 0; // equal
cur1 = ptr1;
cur2 = ptr2;
while (true) {
if (cur2 == NULL || cur1 == ptr2) return -1; // ptr1 before ptr2
if (cur1 == NULL || cur2 == ptr1) return 1; // ptr2 before ptr1
cur1 = cur1->next;
cur2 = cur2->next;
}
}
All this assumes that the given pointers are both pointing to members of the same linked list. With the above function you can now do:
// ...
int res = compare(ptr1, ptr2);
if (res < 0) output("*ptr1 comes before *ptr2");
if (res > 0) output("*ptr1 comes after *ptr2");
if (res == 0) output("*ptr1 is the same as *ptr2");

Exiting reading two strings with gets in do while loop

I am trying to ask a user to type two strings and then the system makes some action as concatenation.
The program I want to be executed at least once and when the first string is equal to '0' to exit.
Could you please help me do it ?
Because something I make wrong.
#include<stdio.h>
int main()
{
char s1[100],s2[100];
int len = 0;
do
{
len = strlen(s1);
printf("\nString1:");
gets(s1);
printf("String2:");
gets(s2);
} while(s1[0] == '0' && s1[len-1] =='\0');
return 0;
}
Thanks in advance
As per the condition (s1[0] == '0' && s1[len-1] == '\0') the loop will continue only if the first string is '0' and the second string is blank. For all other inputs the loop will exit.
I think your requirement is the condition (s1[0] != '0')

How to refresh QAbstractSpinBox?

I need QSpinBox for unsigned int. Therefore I have wrote simple class:
class UnsignedSpinBox : public QAbstractSpinBox {
private:
uint32_t value = 0;
uint32_t minimum = 0;
uint32_t maximum = 100;
private:
void stepBy(int steps) {
if (steps < 0 && (uint32_t)(-1 * steps) > value - minimum)
value = minimum;
else if (steps > 0 && maximum - value < (uint32_t)steps)
value = maximum;
else
value += steps;
lineEdit()->setText(QString::number(value));
}
StepEnabled stepEnabled() const {
if (value < maximum && value > minimum)
return QAbstractSpinBox::StepUpEnabled | QAbstractSpinBox::StepDownEnabled;
else if (value < maximum)
return QAbstractSpinBox::StepUpEnabled;
else if (value > minimum)
return QAbstractSpinBox::StepDownEnabled;
else
return QAbstractSpinBox::StepNone;
}
QValidator::State validate(QString &input, int &) const {
if (input.isEmpty())
return QValidator::Intermediate;
bool ok = false;
uint32_t validateValue = input.toUInt(&ok);
if (!ok || validateValue > maximum || validateValue < minimum)
return QValidator::Invalid;
else
return QValidator::Acceptable;
}
public:
UnsignedSpinBox(QWidget* parent = 0) : QAbstractSpinBox(parent) {
lineEdit()->setText(QString::number(value));
}
virtual ~UnsignedSpinBox() { }
};
In gerenal it works fine but it has one shortcoming. Step buttons are refreshed only after mouse moving (althouth function stepEnabled is called every second). As a result if I hold Page Up, my spin box gets maximum value and these step buttons don't change their state until I move my mouse. Or if value is 0, one pressing of Page Up or up arrow key on a keyboard changes value and text, but doesn't change buttons' state (down button is still disabled). Moreover, when value == maximum both buttons are disabled although function stepEnabled returnes QAbstractSpinBox::StepDownEnabled (I've checked it). What am I doing wrong? How can I enforce QAbstractSpinBox to draw these buttons correctly?
P.S. I use Debian. But I don't think it does matter since QSpinBox works fine
I think the Qt on your platform is either too old or otherwise broken. It works fine on OS X, on both Qt 4.8.5 and Qt 5.2.0.
There are two other solutions:
If you don't care about full range of unsigned integer, simply use QSpinBox and set non-negative minimum and maximum. That's all. On platforms with 32 bit int, maximum int value is 2^31-1, that's about half of the maximum uint value of 2^32-1.
You can use QDoubleSpinBox. On sane platforms you care about, double has more than 32 bits of mantissa, so you can convert it to a quint32 without loss of precision.
If you want to be sure, just add static_assert(sizeof(double)>4) anywhere in your code.
If one worries about performance, then it really doesn't matter. The calculations are performed at the rate of user input events: that's a couple dozen double operations per second. It doesn't matter.

QGraphicsItem: Why no `stackAfter` method?

I'm having an annoying time trying to get around the 'recommended' way of doing something.
So, I have a stack of cards. I want to make it so that when I deal a card, it becomes the last-drawn object of the entire scene (typical bring_to_front functionality).
The recommended way to do this is just adding to the object's zValue until it is larger than all the rest, but I was hoping to do away with rather "lazy" integers running around all over the place with judicious use of the stackBefore method, which simulates reorganizing the order in which objects were added to the scene.
This works perfectly fine when I shuffle my cards in a limited set (get list of selected items, random.shuffle, for item do item.stackBefore(next item)), but it is certainly not working when it comes to bubbling the card to the top of the entire scene.
I considered adding a copy of the object to the scene and then removing the original, but it just seems like I should be able to do stackAfter like I would when using a Python list (or insertAt or something).
Sample code:
def deal_items(self):
if not self.selection_is_stack():
self.statusBar().showMessage("You must deal from a stack")
return
item_list = self.scene.sorted_selection()
for i,item in enumerate(item_list[::-1]):
width = item.boundingRect().width()
item.moveBy(width+i*width*0.6,0)
another_list = self.scene.items()[::-1]
idx = another_list.index(item)
for another_item in another_list[idx+1:]:
another_item.stackBefore(item)
This works. It just seems somewhat... ugly.
self.scene.items returns the items in the stacking order (link). So if you want to stackAfter an item, you can just query the z value of the current topmost item and then set the z value of the new topmost card to a value one larger.
item.setZValue(self.scene.items().first().zValue() + 1)
Hope that helps.
Edit added src for stackBefore and setZValue from http://gitorious.org/qt/
src/gui/graphicsview/qgraphicsitem.cpp
void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)
{
if (sibling == this)
return;
if (!sibling || d_ptr->parent != sibling->parentItem()) {
qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
return;
}
QList<QGraphicsItem *> *siblings = d_ptr->parent
? &d_ptr->parent->d_ptr->children
: (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0);
if (!siblings) {
qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
return;
}
// First, make sure that the sibling indexes have no holes. This also
// marks the children list for sorting.
if (d_ptr->parent)
d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
else
d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();
// Only move items with the same Z value, and that need moving.
int siblingIndex = sibling->d_ptr->siblingIndex;
int myIndex = d_ptr->siblingIndex;
if (myIndex >= siblingIndex) {
siblings->move(myIndex, siblingIndex);
// Fixup the insertion ordering.
for (int i = 0; i < siblings->size(); ++i) {
int &index = siblings->at(i)->d_ptr->siblingIndex;
if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
++index;
}
d_ptr->siblingIndex = siblingIndex;
for (int i = 0; i < siblings->size(); ++i) {
int &index = siblings->at(i)->d_ptr->siblingIndex;
if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
siblings->at(i)->d_ptr->siblingOrderChange();
}
d_ptr->siblingOrderChange();
}
}
void QGraphicsItem::setZValue(qreal z)
{
const QVariant newZVariant(itemChange(ItemZValueChange, z));
qreal newZ = newZVariant.toReal();
if (newZ == d_ptr->z)
return;
if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
// Z Value has changed, we have to notify the index.
d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
}
d_ptr->z = newZ;
if (d_ptr->parent)
d_ptr->parent->d_ptr->needSortChildren = 1;
else if (d_ptr->scene)
d_ptr->scene->d_func()->needSortTopLevelItems = 1;
if (d_ptr->scene)
d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
itemChange(ItemZValueHasChanged, newZVariant);
if (d_ptr->flags & ItemNegativeZStacksBehindParent)
setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0));
if (d_ptr->isObject)
emit static_cast<QGraphicsObject *>(this)->zChanged();
}

A Boolean recursive function to tell if a digit appears in an integer an even number of times

The function gets an integer and a digit, and should return true
if the digit appears an even number of times in the integer, or false if not.
For example:
If digit=1 and num=1125
the function should return true.
If digit=1 and num=1234
the function should return false.
bool isEven(int num, int dig)
{
bool even;
if (num < 10)
even = false;
else
{
even = isEven(num/10,dig);
This is what I've got so far, and I'm stuck...
This is homework so please don't write the answer but hint me and help me get to it by myself.
To set up recursion, you need to figure out two things:
The base case. What is are the easy cases that you can handle outright? For example, can you handle single-digit numbers easily?
The rule(s) that reduce all other cases towards the base case. For example, can you chop off the last digit and somehow transform the solution for the remaning partial number into the solution for the full number?
I can see from your code that you've made some progress on both of these points. However, both are incomplete. For one thing, you are never using the target digit in your code.
The expression num%10 will give you the last digit of a number, which should help.
Your base case is incorrect because a single digit can have an even number of matches (zero is an even number). Your recursive case also needs work because you need to invert the answer for each match.
This funtion isEven() takes a single integer and returns the true if the number of occurence of numberToCheck is even.
You can change the base as well as the numberToCheck which are defined globally.
#include <iostream>
using std::cout;
using std::endl;
// using 10 due to decimal [change it to respective base]
const int base = 10;
const int numberToCheck = 5;
//Checks if the number of occurence of "numberToCheck" are even or odd
bool isEven(int n)
{
if (n == 0)
return 1;
bool hasNumber = false;
int currentDigit = n % base;
n /= base;
if (currentDigit == numberToCheck)
hasNumber = true;
bool flag = isEven(n);
// XOR GATE
return ((!hasNumber) && (flag) || (hasNumber) && (!flag));
};
int main(void)
{
// This is the input to the funtion IsEven()
int n = 51515;
if (isEven(n))
cout << "Even";
else
cout << "Odd";
return 0;
}
Using XOR Logic to integrate all returns
// XOR GATE
return ((!hasNumber) && (flag) || (hasNumber) && (!flag));

Resources