Hi I need to draw a rectangle over Qlabel, as a first step I am trying to get the mouse events. Using below code the event get called but the co-ordinates are always same even if I changed the mouse position.
Also I need to set the mouse tracking only on the Qlabel, and it's working fine except the mouse release, the function mouseReleaseEvent getting called when the mouse released outside the Qlabel.
Also please see the comments in the below code,
ImageEditer::ImageEditer(QWidget *parent) :
QDialog(parent),
ui(new Ui::ImageEditer)
{
ui->setupUi(this);
ui->label_image->setMouseTracking(true); // need to set the mouse tracking over this label
}
void ImageEditer::mouseMoveEvent(QMouseEvent* event)
{
qDebug() << "Mouse move.." << pos() << "---> " << x() << "," << y(); // these printing same values
}
void ImageEditer::mousePressEvent(QMouseEvent* event)
{
qDebug() << "Mouse press.." << pos() << "---> " << x() << "," << y(); // these printing same values
}
// This getting called when release the mouse outside the label_image
void ImageEditer::mouseReleaseEvent(QMouseEvent *event)
{
qDebug() << "Mouse release.." << pos() << "---> " << x() << "," << y(); // these printing same values
}
You are printing pos(), x(), y() of the widget.
Just change it to event->pos(), event->pos().x(), event->pos().y()
Related
When I debug the pcl documentation visualization mouse event function code as following shows:
viewer->registerMouseCallback(mouseEventOccurred, (void*)&viewer);
void mouseEventOccurred(const pcl::visualization::MouseEvent &event,void* viewer_void)
{
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer = *static_cast<boost::shared_ptr<pcl::visualization::PCLVisualizer> *> (viewer_void);
if (event.getButton() == pcl::visualization::MouseEvent::LeftButton &&
event.getType() == pcl::visualization::MouseEvent::MouseButtonRelease)
{
std::cout << "Left mouse button released at position (" << event.getX() << ", " << event.getY() << ")" << std::endl;
char str[512];
sprintf(str, "text#%03d", text_id++);
viewer->addText("clicked here", event.getX(), event.getY(), str);
}
}
If I remove the code:
viewer->addText("clicked here", event.getX(), event.getY(), str);
It would work well, or I encountered an error:
I do not know how to solve this problem. Thanks!
After I clicked the Retry, the exception shows as:
Exception
I've just recently learned how to get my mouse position but if I move my window it is having a problem. Example, I want to draw a dot in the position of the mouse coordinate (x = 100, y = 100) so the system will draw at that coordinate in the window and that's the problem because, the mouse position is read according to the position of the SCREEN instead of the WINDOW. If I can somehow get the mouse coordinate according to the window instead of the screen that would fix the problem.
#include<graphics.h>
#include<iostream>
#include<windows.h>
using namespace std;
int main()
{
initwindow(800,600);
POINT CursorPosition;
while(1)
{
GetCursorPos(&CursorPosition);
cout << CursorPosition.x << endl;
cout << CursorPosition.y << endl;
if(GetAsyncKeyState(VK_LBUTTON)) {
bar(CursorPosition.x, CursorPosition.y, CursorPosition.x+50,
CursorPosition.y+50);
}
delay(5);
Sleep(5);
system("cls");
}
}
Here is a simple solution which shows you how to convert cursor position to window position. This Proof of Concept utilizes GetForeGroundWindow(), GetCursorPosition() and ScreenToClient(). Hold right mouse button and move your mouse around the console window to see the output
#include <iostream>
#include <windows.h>
int main()
{
while (1)
{
if (GetAsyncKeyState(VK_RBUTTON))
{
POINT pnt;
GetCursorPos(&pnt);
ScreenToClient(GetForegroundWindow(), &pnt);
std::cout << "x: " << pnt.x << " y: " << pnt.y << std::endl;
Sleep(300);
}
}
return 0;
}
Pretty much as the tittle says, when i drag an item from QTableWidget it adds a child to ui->table->children, and then it launches ChildAdded event to my eventFilter, the problem is that if i drop the dragged item into an area that doesn't accept dropping that child won't be removed from ui->table->children whereas releasing the dragged item within an area that has dropping enabled it will, and also launches ChildRemoved event.
Here is my init code:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
m_ui(new Ui::MainWindow)
{
m_ui->setupUi(this);
m_ui->left_table->installEventFilter(this);
m_ui->right_table->installEventFilter(this);
m_ui->left_table->setColumnCount(1);
m_ui->left_table->setRowCount(25);
m_ui->left_table->setHorizontalHeaderLabels({"Source"});
m_ui->left_table->horizontalHeader()->setStretchLastSection(true);
m_ui->left_table->setAcceptDrops(false);
m_ui->left_table->setDragEnabled(true);
m_ui->right_table->setColumnCount(1);
m_ui->right_table->setHorizontalHeaderLabels({"Receiver"});
m_ui->right_table->horizontalHeader()->setStretchLastSection(true);
m_ui->right_table->setAcceptDrops(true);
for (int i = 0; i < 25; ++i) {
m_ui->left_table->setItem(i, 0, new QTableWidgetItem(QString::number(i)));
}
qDebug() << "Left childs: " << m_ui->left_table->children().size();
}
and the event filter:
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::ChildAdded || event->type() == QEvent::ChildRemoved) {
qDebug() << "Object: " << watched->objectName()
<< " Event: " << event->type()
<< "Childs: " << m_ui->left_table->children().size();
}
return false;
}
Example of dropping on invalid area, this wont remove the child added before:
Example of dropping on valid area, this will remove the child and call the ChildRemoved event:
I have a folder with many images, I've loaded the filenames into a vector of string and want to display the images in a GTK::Image component like a video, 25 frames (images) per second. But I the component don't re-draw after run the app.
I call the queue_draw(), but nothing change. How I do it?
EDIT:
The main function is like:
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create("org.gtkmm.example");
refBuilder = Gtk::Builder::create();
try{
refBuilder->add_from_file("main_window2.glade");
}
catch(const Glib::FileError& ex){
std::cerr << "FileError: " << ex.what() << std::endl;
return 1;
}
catch(const Glib::MarkupError& ex){
std::cerr << "MarkupError: " << ex.what() << std::endl;
return 1;
}
catch(const Gtk::BuilderError& ex){
std::cerr << "BuilderError: " << ex.what() << std::endl;
return 1;
}
refBuilder->get_widget("main_window", main_window);
cout << "window: " << main_window << endl;
if(main_window)
{
Gtk::ImageMenuItem* newButton = nullptr;
Gtk::ImageMenuItem* openButton = nullptr;
Gtk::ImageMenuItem* saveButton = nullptr;
Gtk::Button* playButton = nullptr;
refBuilder->get_widget("new_button", newButton);
refBuilder->get_widget("open_button", openButton);
refBuilder->get_widget("save_button", saveButton);
refBuilder->get_widget("play_button", playButton);
refBuilder->get_widget("image_container", container);
refBuilder->get_widget("image_component", image_component);
if(playButton)
playButton->signal_clicked().connect(sigc::ptr_fun(on_image_draw));
if(newButton)
newButton->signal_activate().connect( sigc::ptr_fun(on_new_button_activate) );
if(openButton)
openButton->signal_activate().connect( sigc::ptr_fun(on_open_button_activate) );
if(saveButton)
saveButton->signal_activate().connect( sigc::ptr_fun(on_save_button_activate) );
cout << "running main window" << endl;
app->run(*main_window);
}
delete main_window;
And when clicked in playButton, the drawing code is called
static void on_image_draw(){
string path = video.getDirectory();
string aux = path + "/";
cout << "reproduzindo: " << aux << endl;
vector<string> vetor = video.get_imageVector();
cout << "vetor" << endl;
for(auto frame: video.get_imageVector()){
aux += frame;
cout << "frame: " << aux << endl;
image->clear();
image->set(aux);
Glib::RefPtr<Gdk::Pixbuf> pix = image->get_pixbuf();
pix = pix->scale_simple(WIDTH, HEIGHT, Gdk::INTERP_BILINEAR);
image->set(pix);
image->queue_draw();
aux = path+"/";
sleep(1);
}
}
You're not supposed to draw all your frames in the draw signal handler. You basically need to set the image, then call queue_draw. You're doing this right, but then you must let GTK+ do its part of the work. You can't just loop: calling queue_draw puts a draw event in the main loop that GTK+ needs to process to draw your image.
Remember you are single-threaded, so the CPU is like a shovel. When you are in a callback, you get the shovel and do your work. You can't expect GTK+ to process the events you send to it if you don't give it the shovel back.
Here's how you're supposed to architcture this stuff. Please keep in mind that if you need 25fps, this approach is sub-optimal, and you should probably give a look at video libraries like gstreamer.
So when you press play, you're supposed to trigger an event source like a timer or idle handler. That's because you need something to say: I need to isplay a new image. Give a look at g_timeout_add or g_idle_add in the GLib for that (I know only the names for the C api, find the equivalent ones in gtkmm).
Then in the callback associated to that timeout or idle event, you set your image (a single one, no loop), and that's all. Not sure calling queue_draw is even required. It would be if you were drawing by hand in a GtkDrawingArea, but as that's a GtkImage, so by setting a new image you say implicitely that the image has changed and should be redrawn.
I have a custom button that can be right clicked in addition to left clicking. It works like this:
private slots:
void mousePressEvent(QMouseEvent *e) {
if(e->button() == Qt::RightButton) {
std::cout << "kek2";
emit rightClicked();
}
QPushButton::mousePressEvent(e);
}
For some weird reason left click works fine, and right clicks are not processed (judging by lack of kek2 outputs) until I do a left click, upon which all right clicks are processed at once. Why?
I had a look at it and implemented an equivalent Button and changed your code to this:
void QRightClickButton::mousePressEvent(QMouseEvent *e)
{
if(e->button() == Qt::RightButton) {
std::cout << "kek2" << std::endl; //the << std::endl; //made it work good again
emit rightClicked();
} else if(e->button() == Qt::LeftButton) {
//this else if block is just a fast implementation of the leftclick
std::cout << "kek3" << std::endl;
QPushButton::mousePressEvent(e);
}
}
Try it yourself both log messages ("kek2" as well as "kek3") appear instantly.
Without the << std::endl; it is still buggy!
EDIT: I decided to add 2 more ways to do it!
You can also use it without std::endl;
std::cout << message; //prints message
std::cout.flush(); //flushes the output so it will be visible as well
For example you can create your own class or your own function.
Use qDebug(). qDebug automatically flushes the stream so you don't have to write extra code as well as it belongs to Qt self. That means you're not going to mix 2 libraries.
Use it that way:
qDebug() << message;
You should use qDebug() since it ensures that the output is immediately flushed. std::cout doesn't have to. E.g. qDebug() << "kek2". When using Qt, don't use std::cout for debug output, it's not worth it.
mousePressEvent is not a slot.