I know a position within a QWidget where I would like to draw a caret.
Calling paint redraws the entire widget, and I only want to redraw that one 'box' containing the caret/character. Is there a way to tell it not to erase the entire widget?
How do I create a timer that will cause it to blink (even when the program is doing something else)?
I am looking to do it manually, not through QTextLayout.
QWidget has a repaint() method to repaint only a certain portion of the widget
QWidget.repaint (self, int x, int y, int w, int h)
QWidget.repaint (self, QRect)
QWidget.repaint (self, QRegion)
You can create a QTimer that will fire at intervals:
timer = QtCore.QTimer()
timer.timeout.connect(doBlinkMethod)
timer.start(1000) # every second
def doBlinkMethod():
print "blah"
You could also implement your widgets own built in timer to just act on itself internally:
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qobject.html#startTimer
Related
I'm trying to draw a picture to the screen repeatedly from inside an infinite loop. When I try to draw the picture to the QGraphicsView, it doesn't update unless I break from the loop. Here is my function with the infinite loop:
void MainWindow::displayNoise() {
QImage noise(WIDTH, HEIGHT, QImage::Format_RGB32);
float t = 0;
while (true) {
// Populate noise
rendered_image = noise;
DisplayQImage(rendered_image);
t += 0.200;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
And here is DisplayQImage():
void MainWindow::DisplayQImage(QImage &i)
{
QPixmap pixmap(QPixmap::fromImage(i));
graphics_scene.addPixmap(pixmap);
graphics_scene.setSceneRect(pixmap.rect());
ui->scene_display->setScene(&graphics_scene);
}
Note that graphics_scene and rendered_image are members of MainWindow. If I insert a break statement after my call to DisplayQImage then the first frame renders, but if I don't exit the displayNoise function then the widget doesn't update. I set up a signal so that when I press N it calls displayNoise, and I know the loop is looping. Why isn't the picture showing?
It is because you are not giving the eventloop time to do it's thing. Your function is being called from the eventloop, and the rendering is called from the same eventloop, because they live in the same thread. So you have two options:
write your code in an asyncronous way, eg. with a QTimer.
manually call the eventloop: https://doc.qt.io/qt-5/qeventloop.html#processEvents
I think the first option is probably the nicest way.
I didn't find a proper solution to this problem, so I hope somebody can give me an answer to my problem:
I am using a normal QTreeWidget, but as items I use an own subclass of QTreeWidgetItem (because I needed to store some other information in the item). Now I want to use the itemClicked() signal by the QTreeWidget, but I think my slot doesn't get any signal and I think it has to do with the signature of itemClicked(), since it sends a QTreeWidgetItem and of course not my own subclass.
Is it possible that QTreeWidget doesn't detect a click on my own subclass items?
Here is my connection:
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *)), this, SLOT(displayTransformData(QTreeWidgetItem*)));
And here is my slot:
void GUI::displayTransformData(QTreeWidgetItem* item) {
cout << "test" endl;
Q_actorTreeWidgetItem* actor_item = dynamic_cast<Q_actorTreeWidgetItem*>(item);
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor = actor_item->getActorReference();
double* position = new double[3];
position = actor->GetOrigin();
x_loc->setText(QString(std::to_string( position[0]).c_str() ));
}
I'm already trying to cast the item that I could get from the signal into my own subclass, but the slot function is never called, because the test from my cout line doesn't appear in the console.
I'm very grateful for every help!
The problem is your incorrect SIGNAL specification,
SIGNAL(itemClicked(QTreeWidgetItem *))
You should probably see a warning message at the console along the lines of:
QObject::connect: No such signal
tree_widget::itemClicked(QTreeWidgetItem *) in ...
From the documentation the actual signal spec is
void QTreeWidget::itemClicked(QTreeWidgetItem *item, int column)
So, using the old Qt4 syntax you need
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)),
this, SLOT(displayTransformData(QTreeWidgetItem*)));
If possible, however, you should make use of the newer Qt5 signal/slot syntax
connect(treeWidget, &QTreeWidget::itemClicked, this, &GUI::displayTransformData);
I am loading .ui files via QUiloader, and showing the GUI in my application.
QWidget *mywidget = loader.load(file, this);
QList<QWidget*> wlist = mywidget.findChildren<QWidget *>()
I would like to know what is the text on QPushbutton. I know there is a method text() to get a text from Pushbutton, but it is not accessible when I do:
QString btext = wlist.at(1).text();
Any idea how I can get the text from QPushbutton, and other Widgets, when they grouped as QWidget?
Thanks.
You should search for QPushButtons instead of QWidgets:
QList<QPushButton*> blist = widget.findChildren<QPushButton*>();
Still your code wouldn't compile. The last line should read:
QString btext = blist.at(1)->text();
Using -> since you are accessing a pointer, not the widget. Also you should check if the findChildren() function actually returnes enough buttons. You would get a crash or assertions when accessing a list item by an invalid index.
Also please note that at(1) does not return the first but the second item in the list (lists start from 0).
Update: If you search for QWidgets and cast each of them you need to take care of getting a nullptr:
QList<QWidget*> wlist = widget.findChildren<QWidget*>();
foreach (QWidget* w, wlist)
{
QPushButton* b = dynamic_cast<QPushButton*>(w);
// If "w" is not a button "b" is nullptr
if (b)
{
QString btext = b->text();
}
}
I used Qt Creator to make a "keyboard" window with sixty QPushButtons and one QLineEdit. How can I make the buttons to add characters into QLineEdit text box? If I press a QPushButton with the label 'Q' on it, I want the program to add the Unicode character 'Q' on the text box.
One way to do this would be to just connect the 'clicked' signal from all the buttons to a slot, and then handle the adding of the character there.
For example, if the all keyboard buttons are inside a layout called 'buttonLayout', in your MainWindow constructor you can do this:
for (int i = 0; i < ui->buttonLayout->count(); ++i)
{
QWidget* widget = ui->buttonLayout->itemAt( i )->widget();
QPushButton* button = qobject_cast<QPushButton*>( widget );
if ( button )
{
connect( button, SIGNAL(clicked()), this, SLOT(keyboardButtonPressed()) );
}
}
Then in the slot implementation, you can use QObject::sender(), which returns the object that sent the signal:
void MainWindow::keyboardButtonPressed()
{
QPushButton* button = qobject_cast<QPushButton*>( sender() );
if ( button )
{
ui->lineEdit->insert( button->text() );
}
}
OPTION 1 - Multiple signals and slots
Connect all pushbuttons clicked() signal to a slot
// Let button01 be the A
connect(ui->button01, SIGNAL(clicked()), this, SLOT(buttonClicked()));
...
// Let button 60 be the Q
connect(ui->button60, SIGNAL(clicked()), this, SLOT(buttonClicked()));
In the buttonClicked() slot you have to figure out which button was clicked and append the corresponding letter to the line edit.
void buttonClicked()
{
QObject* callingButton = QObject::sender();
if (callingButton == button01)
ui->lineEdit->setText(ui->lineEdit->text()+ "A");
...
else if (callingButton == button60)
ui->lineEdit->setText(ui->lineEdit->text()+ "Q");
}
OPTION 2 - Subclass QPushButton
You could subclass QPushButton in order to avoid the multiple ifs. In your subclass just catch the mouse release event and emit a new signal which will contain the button's text
void KeyboardButton::mouseReleaseEvent(QMouseEvent* event)
{
emit clicked(buttonLetter); // Where button letter a variable of every item of your subclass
}
Similarly connect the clicked(QString) signal with a slot
connect(ui->button01, SIGNAL(clicked(QString)), this, SLOT(buttonClicked(QString)));
...
connect(ui->button60, SIGNAL(clicked(QString)), this, SLOT(buttonClicked(QString)));
void buttonClicked(QString t)
{
ui->lineEdit->setText(ui->lineEdit->text()+ t);
}
I have created an application with a similar issue, trying to convert the qpushbutton text to the qlineedit itself. The key is how you initialize the buttons and to use polymorphism in your function. To create an emit signal wont work for individual characters. The .digitValue will work if the case if for numerics (which the buttons would be of type int), but qt doesnt have a character value (I should say after 6hrs of reading qt doc and another 4 of trying different combinations it would not work), I think it has to do with how many bits it takes to store each variable type in an array. I even tried converting the button->text to QString to use with the emit function as a signal prototyped.
I do not know what your button layout is, but I will give you a synopsis of what I did. I first created a global, static const char array containing all the letters needed e.g.
static const char vowelarray[] = "AEIOU";
Then initialized the QPushButtons with in the MainWindow function, using iteration, setting a for loop's terminating condition equal to the size char array (in your case 60?). This all depends on your button layout though. I personally created a void function (setLocation) for the button->setGeometry of each button and iterated the setGeometry, and then passed the function to the MainWindow Function, at end of fucntion. The following code was used to initialize the buttons, connect signals to slots, and use polymorphism to connect to lineedit.
for (int i = 0; i < 26; i++){
characterButton[i] = new QPushButton(chararry[i], this); `
characterButton[i] -> setStyleSheet("QPushButton{background: grey; color: brown}");
connect(characterButton[i],SIGNAL(released(),this,SLOT(characterPushed()));
}
setLocation();
Then created a void function (e.g. void MainWindow::characterPuched()) where the following code was used:
void MainWindow::characterPushed(){
QPushButton *characterButton = (QPushButton*) sender();
if (characterButton )
{
lineEdit -> setText(letters.insert(letters.size(), characterButton -> text()));
}
lineEdit -> setText(letters);
}
of course letters was a global variable as well as:
QString letters = "";
and of course the QPushButtons and the function were prototype in the header file as a private variables and slots, e.g.
private:
QPushButton *characterButton[26];
the variable 'letters' was used to extract and input text to and from the line edit for further functions throughout the application.
Best Luck!!``
i m facing problem in giving animation to progressbar in QT.
where is the mistake in the following code, i am getting continues progress bar, but its not animating
QApplication a(argc, argv);
QProgressDialog *dialog = new QProgressDialog();
QProgressBar *pbar = new QProgressBar(dialog);
pbar->setMinimum(0);
pbar->setMaximum(0);
pbar->setTextVisible(false);
QDesktopWidget *desktop = QApplication::desktop();
QRect rect = desktop->geometry();
pbar->setGeometry(rect.left(),rect.top(),rect.right(),rect.bottom()-300);
pbar->show();
dialog->setBar(pbar);
dialog->showMaximized();
dialog->exec();
return a.exec();
I tried this code on WinXP with Qt 4.5.3 and it works as expected.
I cannot give you a solution but i have a suggestion:
You don't need to set a QProgressBar to QProgressDialog, it already has its own.
Removing the code for QProgressBar, the code below does the same thing with your original code on my machine.
QApplication a(argc, argv);
QProgressDialog *dialog = new QProgressDialog();
dialog->setMinimum(0);
dialog->setMaximum(0);
dialog->showMaximized();
dialog->exec();
return a.exec();
If you're using the Windows Vista theme (QWindowsVistaStyle) then there's a bug that means indeterminate progress bars don't animate. I've written up the bug here, complete with simple patch: http://bugreports.qt-project.org/browse/QTBUG-10984
Dudes, what exactly do you think that a progress bar does? It is supposed to show the user that an activity is ongoing and also what is the current progress state.
Your code
QProgressDialog *dialog = new QProgressDialog();
dialog->setMinimum(0);
dialog->setMaximum(0);
would indicate that a certain operation will start with status 0 and will end when the status (or current value) reaches value ... 0. And you want some animation going with that?
See an example at http://doc.trolltech.com/4.6/qprogressdialog.html#details
Basically you should create a progress dialog with a min and a max value
QProgressDialog *dialog = new QProgressDialog();
dialog->setMinimum(0);
dialog->setMaximum(100);
Then have the actual progress value updated (e.g. on a timer which triggers the perform slot) in order to have it represented in the progress bar:
void Operation::perform()
{
dialog->setValue(steps);
//... perform one percent of the operation
steps++;
if (steps > dialog->maximum())
t->stop();
}
A series of updates, with progressively increasing progress value, will create the animation effect you want.
Obviously tagging this with Symbian is pure wrong, this is not at all Symbian specific. Nor is it Qt 4.x specific, hell ... it's not even Qt specific, it's basically a logic issue. ;)