How do I call a box.redraw from a routine?
I have a timer callback from which I a have to assign a new picture to box1.
My programm crashes at this point.
...
Fl_Window *win = NULL;
Fl_Box *box1 = NULL;
static void get_new_pic(void*) { // Timer callback
const char *filename = "pic2.png";
Fl_PNG_Image png(filename);
box1->image(png);
box1->redraw(); // this kicks the application
Fl::repeat_timeout(2,CB_Hole_Info);
}
int main() {
win = new Fl_Window(240,240); // make a window
box1 = new Fl_Box(0,0,240,180); // widget that will contain image
const char *filename = "pic1.png";
Fl_PNG_Image png(filename);
box1->image(png);
Fl::add_timeout(2, get_new_pic, buff); // setup a timer
win->show();
return(Fl::run());
}
Regards
Your way of adding the image in the timeout is correct. However, you allocate the image on the stack: Fl_PNG_Image png(filename);, so when you leave the timer, the image is automatically deleted together with the stack. When the box is actually drawn, the image is not there anymore.
FLTK does not copy the image. It just links to it.
You'd have to write Fl_PNG_Image *png = new Fl_PNG_Image(filename); and fix the rest of the code to use a pointer and make sure that the image is deleted at the very end.
You declared png1 and png2 as global variables (used in get_new_pic()) but you also declared local variables with the same name in main() which "shadow" the global variables.
Please remove Fl_PNG_Image * from the two assignments in main() so these assignments use the global variables as intended.
Hint: you should also assign a solid background to the box like
box1->box(FL_FLAT_BOX);
Related
So my question is: I'm trying to make a "carousel" of images (select image from file, load it and display it using "next_button" or load the previous one using "previous_button"). My problem is that i have no clue how to access the same window, I have defined at main, so I can attach the selected picture.
I tried passing my_Window& win but I get an error at cb_next saying that I cannot use this type (struct)
Any ideas would be greatly appreciated. Thank you very much for your valuable time!
Here is a sample of the code:
struct my_Window : Graph_lib :: Window
{
//Defined buttons
//...
//Example of how I create and call the next_button(to display the next picture)
static void cb_next(Address, Address); // callback for next_button
void next();
};
//Here is what I use to make the button work
void my_Window::cb_next(Address, Address pw)
{
reference_to<my_Window>(pw).next(); //cannot pass my_Window
}
void my_Window::next()
{
//Load the next picture!
//This is where I want to attach the image
//but when I use attach(image) it doesn't know where to attach ( as expected)
redraw();
}
int main()
{
my_Window win(Point(100,100),800,600,"Images"); //I want this "win" to be accessed by the next button so I can attach the new picture.
return gui_main();
}
It's more of a C++ question.
Why is cb_next() a static method?
If you make it a normal method, you can access the same struct/window you defined in main using the this pointer. Writing this is also optional, you already call redraw in the next() method, which is actually this->redraw();.
I created a sample GTKMM project on GNOME Builder. The great thing was that a sample hello world code was automatically generated for my sample project. Since C++ source files are organized into three parts:
Header file
Implementation file
Main file
I've modified my sample code in a single cpp file for demonstration:
#include <iostream>
#include <gtkmm.h>
using std::cout;
using Gtk::Application;
using Gtk::Window;
using Gtk::Box;
using Gtk::Button;
using Gtk::Label;
class HelloWindow : public Window
{
Box box;
Button button;
Label label;
public:
HelloWindow();
~HelloWindow();
};
HelloWindow::HelloWindow()
: Glib::ObjectBase("HelloWindow")
, Window()
, box(Gtk::ORIENTATION_VERTICAL)
, button("Clickable button")
, label("Hello World!")
{
set_default_size(320, 240);
bool expand(true), fill(true);
box.pack_start(label, expand, fill);
box.pack_end(button, expand, fill);
add(box);
show_all();
}
HelloWindow::~HelloWindow()
{
cout << "Object successfully destructed!\n";
}
static void
on_activate(Glib::RefPtr<Application> app)
{
Window *window = app->get_active_window();
if (not window) {
window = new HelloWindow();
window->set_application(app);
app->add_window(*window);
}
window->present();
}
int main()
{
auto app = Application::create("io.test.window-state-event");
app->signal_activate().connect(sigc::bind(&on_activate, app));
return app->run();
}
One interesting part about the above code is that app is connected to on_activate signal which means the user gets to run only one instance of this program. And if he tries to run another instance the previous still running window will instead be presented.
However, there is the use of new keyword on on_activate() and that confuses me a bit. Is the object really deleted when the user closes the HelloWorld window? What I've learnt about C++ new keyword is that one must remember to delete any object allocated with the former keyword.
Moreover, the destructor message "Object successfully destructed!" isn't printed when the window is closed.
Chances are there is an intentional leak, but it's "controlled". The author knows that this method will be called only once. The author also knows the memory needs to be active the entire lifetime of the application. When the application closes, that memory will be freed one way or another (albeit the destructor will never be called, but in this case, there is nothing imperative that would need to be done)
It's perfectly fine in this scenario.
If you want to ensure the Window object gets deleted, you could keep a unique_ptr of the Window and it will dispose itself (thanks to #underscore_d comment):
#include <memory>
static std::unique_ptr<Window> window;
static void
on_activate(Glib::RefPtr<Application> app)
{
if (!window) {
window = std::make_unique<HelloWindow>();
window->set_application(app);
app->add_window(*window);
}
window->present();
}
int main()
{
auto app = Application::create("io.test.window-state-event");
app->signal_activate().connect(sigc::bind(&on_activate, app));
return app->run();
}
At the end of the day, I am sure the author wanted to keep this "Hello, World" example simple and concise and didn't want to add in some code that doesn't really need to be there in order to keep it simple and concise.
Take a look at the section about managed widgets in the GTKMM documentation. You should use some variation of Gtk::make_managed:
if (!window) {
window = Gtk::make_managed<HelloWindow>();
window->set_application(app);
app->add_window(*window);
}
This way, the window's lifetime will be managed by the application.
I am building a gtkmm application. The program open with a setting window asking the user to specify some information, and when sanity checks are done, this window should be closed, and the maih window of the application should open.
Right now, opening the main window, and hiding the setting window completely close the application.
From the setting windows, I am doing:
MainWindow* main_window = new MainWindow();
main_window->show();
this->hide();
How can I get the behavior described above ?
Apparently, you can add and remove windows from a Gtk::App. Would it does what I described, and does it mean I would have to pass to my window the Gtk::App pointer ? Thanks.
What seems to be the proper solution is to pass to the window the application pointer (m_app), add the new window to it, show that window and hide the current one. Removing the current one from the application will let the run() function return:
MainWindow* main_window = new MainWindow(m_app);
m_app->add_window(*main_window);
main_window->show();
this->hide();
m_app->remove_window(*this);
delete->this;
This work, but this might not be the proper way of doing things.
Although the question is quite old, I will show my approach which may help someone else to deal with this task.
I use a general application object which holds all window objects: MainApplication.cpp
MainApplication::MainApplication(int argc, char **argv)
{
// Creating the main application object as first
mainApp = Gtk::Application::create(argc, argv, APPLICATION_ID);
// Create the entry window
createEntryWindow();
}
int MainApplication::run()
{
if (!isRunning) {
// Set the current window to entry window for startup
currentWindow = entryWindow;
return mainApp->run(*entryWindow);
} else {
return -1;
}
}
void MainApplication::createEntryWindow()
{
// Load the entry_window.glade layout with the Gtk::Builder Api
Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("../layout/entry_window.glade");
// Calls the constructor of my own derived widget class which details are specified inside the builder file
builder->get_widget_derived(WND_ENTRY, entryWindow);
// Set this main application object to the new window
entryWindow->setMainApplicationContext(this);
}
MainApplication.h
static const int WS_ENTRY = 100;
static const int WS_SOMETHING = 200;
class MainApplication {
public:
MainApplication(int argc, char* argv[]);
int run();
void switchCurrentWindow(int specifier);
private:
void createEntryWindow();
private:
Glib::RefPtr<Gtk::Application> mainApp;
Gtk::Window* currentWindow = nullptr;
EntryWindow* entryWindow = nullptr;
bool isRunning = false;
};
The MainApplication object will be created inside the main() and after that run() is called: main.cpp
int main(int argc, char* argv[])
{
// Create main application object
MainApplication mainApplication(argc, argv);
// Starts the event loop
// No events propagate until this has been called
return mainApplication.run();
}
The EntryWindow.cpp looks like this (just a simple example):
EntryWindow::EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade)
: Gtk::Window(object), builder(refGlade)
{
// Set widgets to builder
builder->get_widget(btnName, btn);
// Set on click methods for signal_clicked
btn->signal_clicked().connect(sigc::mem_fun(*this, &EntryWindow::onBtnClicked));
}
void EntryWindow::onBtnClicked()
{
mainApplicationContext->switchCurrentWindow(WS_SOMETHING);
}
void EntryWindow::setMainApplicationContext(MainApplication* mainApplication)
{
this->mainApplicationContext = mainApplication;
}
EntryWindow.h:
class EntryWindow : public Gtk::Window {
public:
EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade);
void setMainApplicationContext(MainApplication* mainApplication);
protected:
void onBtnClicked();
protected:
const Glib::RefPtr<Gtk::Builder> builder;
Gtk::Button* btn;
private:
MainApplication* mainApplicationContext = nullptr;
const Glib::ustring btnName = BTN_NAME;
};
So now when the button was clicked, you can switch the windows with following function inside the MainApplication class:
void MainApplication::switchCurrentWindow(int specifier)
{
// Check if the passed specifier exist
int tmpSpecifier = 0;
switch (specifier) {
case WS_ENTRY:
tmpSpecifier = WS_ENTRY;
break;
case WS_SOMETHING:
tmpSpecifier = WS_SOMETHING;
break;
default:
tmpSpecifier = 0;
}
// If the specifier exist
if (tmpSpecifier != 0) {
// Increase the use counter of the main application object
mainApp->hold();
// Hide the current window
currentWindow->hide();
// Remove the current window
mainApp->remove_window(*currentWindow);
} else {
return;
}
switch (tmpSpecifier) {
case WS_ENTRY:
currentWindow = entryWindow;
break;
case WS_SOMETHING:
currentWindow = somethingWindow;
break;
}
// Add the new current window
mainApp->add_window(*currentWindow);
// Show the new window
currentWindow->show();
// Decrease the use counter of the main application object
mainApp->release();
}
Summary: Create an Object which holds all windows. So whenever you need to have a new window, you have to create it inside this object. This main application object will be called by the main() and there it will call run() when the application is ready to start. After that you will handle which window is shown and hidden by the main application object only.
In response to your answer: delete->this is a pure syntax error, and even without ->, writing delete this is usually a code smell. Barring that, what you did seems like it will work, if perhaps not be as intuitive as it could be.
However, doing things in that sequence is not always possible. For example, you may not know what the next Window will be. Perhaps which window opens next depends on an HTTP response that may take a while to arrive.
The general solution is to call Application.hold() before removing the Window. Calling .hold() increments the use count of the GApplication, just as adding a window does. The app quits when its use count is zero. Saying its life is controlled by windows is just a quick way to approximate an explanation of that (and is obviously only relevant to GtkApplication, not the base GApplication). Removing a window decrements the use count.
So, in this case, you would now go from a use count of 2 to 1 - not 1 to 0 - so removing the 1st window would no longer make the app quit. Then, after you add the 2nd window, however much later that occurs, call .release() to remove the extra use count, so the remaining window(s) now exclusively control the application's lifetime again.
I've only just started learning how to use gtkmm, and I'm trying to create an application which can have more than one window open at the same time (think, main window and a control panel).
I decided to create the layout in Glade, if that's of any relevance to this question.
My method of displaying two bottles is more or less this:
Gtk::Window* main_window = nullptr;
Gtk::Window* servsettings = nullptr;
int main(int argc, char* argv[]) {
auto app = ...
auto builder = ... // these are exluded for brevity
builder->add_from_file("../src/design.glade");
builder->get_widget("main", main_window);
builder->get_widget("servsettings", servsettings);
app->run(*servsettings);
app->run(*main_window);
}
Instead of opening two windows, this instead opens servsettings, then segfaults when I close that.
Now forgetting about the segfault (I'm utterly confused about that,) I think I can see why it only opens servsettings - I assume this is because I'm running the app, and then that call only exits when the window dies?
The problem is, I can't think of any other way to do it. I experimented with multithreading but decided that it would be better to ask here first.
Before anyone suggests it, this answer does not help me. This is because they had a scope-based issue. I don't.
Use Gtk::Application::add_window(Gtk::Window&).
If all the windows managed by Gtk::Application are closed (hidden) or removed from the application then the call to run() will return.
#include <gtkmm.h>
Gtk::Window* window1, *window2;
int main()
{
auto app = Gtk::Application::create();
Gtk::Button button1("Quit"), button2("Quit");
window1 = new Gtk::Window();
window2 = new Gtk::Window();
button1.signal_clicked().connect(sigc::mem_fun(window1, &Gtk::Window::close));
button2.signal_clicked().connect(sigc::mem_fun(window2, &Gtk::Window::close));
window1->set_default_size(200, 200);
window1->add(button1);
window1->show_all();
window2->set_default_size(200, 200);
window2->add(button2);
window2->show_all();
app->signal_startup().connect([&]{
app->add_window(*window2);
});
return app->run(*window1);
}
I found the answer. For those wondering, I replaced the two app->runs with:
servsettings->show();
main_window->show();
app->run(*main_window);
I am struggling with memory issues, I think I missed something and would greatly appreciate if someone can point me to what I understand/do wrong.
What I want to do
My gui runs in the main thread. I am launching a computation on a separate thread T. The result of this computation is a bunch of opencv images. I want to display them in my gui during the computation.
How I understand I should do it
Launch computation thread.
When a new image is computed, convert it to a QImage, wrap it in a custom QEvent, and post it to my gui.
Only use heap memory.
How I implemented it
In my computation thread, when a new image is ready :
std::shared_ptr<cv::Mat> cvimRGB = std::shared_ptr<cv::Mat>(new cv::Mat);
cv::Mat cvimBGR;
cv::Mat cvim = MyNewComputedImage;
cvim.convertTo(cvimBGR,CV_8UC3);
cv::cvtColor(cvimBGR,*cvimRGB,cv::COLOR_BGR2RGB);
std::shared_ptr<QImage> qim = std::shared_ptr<QImage>(
new QImage((uint8_t*) cvimRGB->data,cvimRGB->cols,cvimRGB->rows,cvimRGB->step,QImage::Format_RGB888));
ImageAddedEvent* iae = new ImageAddedEvent(qim,i);
QCoreApplication::postEvent(gui, iae);
In my event handler :
bool mosaicage::event(QEvent * e){
if (e->type() == ImageAdded) {
ImageAddedEvent* ie = dynamic_cast<ImageAddedEvent*>(e);
QImage qim(*(ie->newImage));
QPixmap pm(QPixmap::fromImage(qim));
auto p = scene.addPixmap(pm);
images_on_display.push_back(p);
return true;
} else {
return QWidget::event(e);
}
}
My custom event is defined as follow :
class ImageAddedEvent: public QEvent {
public:
ImageAddedEvent();
~ImageAddedEvent();
ImageAddedEvent(std::shared_ptr<QImage> im, int i);
std::shared_ptr<QImage> newImage;
int index;
};
What happens
In debug mode, I get crap on display.
In release mode, I get an access violation error.
I am pretty confident about the part where I convert cv::Mat to qimage because I did not change it, I used to update the display from the computation thread but I learned better. It worked though (when it did not crash).
How I fixed it
The problem was in the memory pointed by the QImage, which was taken charge of by the cv::Mat I constructed it from. If I want to keep this way of constructing the QImage, using data managed by someone else, I must keep the data valid. Hence I moved the cv::Mat to the custom event :
class ImageAddedEvent: public QEvent {
public:
ImageAddedEvent();
~ImageAddedEvent();
ImageAddedEvent(cv::Mat im, int i);
QImage newImage;
cv::Mat cvim;
int index;
};
I changed the constructor of the event to initialize the QImage with the cv::Mat data :
ImageAddedEvent::ImageAddedEvent(cv::Mat cvimRGB, int i) : QEvent(ImageAdded),
index(i),
cvim(cvimRGB)
{
newImage = QImage((uint8_t*) cvim.data,cvim.cols,cvim.rows,cvim.step,QImage::Format_RGB888);
}
And now I only have to pass a cv::Mat to my event constructor :
cv::Mat cvimBGR,cvimRGB;
cv::Mat cvim = MyNewImage;
cvim.convertTo(cvimBGR,CV_8UC3);
cv::cvtColor(cvimBGR,cvimRGB,cv::COLOR_BGR2RGB);
ImageAddedEvent* iae = new ImageAddedEvent(cvimRGB,i);
QCoreApplication::postEvent(gui, iae);
et voilĂ , again, thanks for the help!
you are using the wrong constructor
from the doc(emph mine):
The buffer must remain valid throughout the life of the QImage and all copies that have not been modified or otherwise detached from the original buffer. The image does not delete the buffer at destruction. You can provide a function pointer cleanupFunction along with an extra pointer cleanupInfo that will be called when the last copy is destroyed.
and you are using the stack allocated cvimRGB for the data pointer which (I believe) will clean up the buffer in it's destructor before the event is handled, leading to accessing "crap" data
so you should create a fresh Qimage and then copy the data
std::shared_ptr<cv::Mat> cvimRGB = std::shared_ptr<cv::Mat>(new cv::Mat);
cv::Mat cvimBGR;
cv::Mat cvim = MyNewComputedImage;
cvim.convertTo(cvimBGR,CV_8UC3);
cv::cvtColor(cvimBGR,*cvimRGB,cv::COLOR_BGR2RGB);
QImage qim = QImage(cvimRGB->cols,cvimRGB->rows,QImage::Format_RGB888));
//copy from cvimRGB->data to qim.bits()
ImageAddedEvent* iae = new ImageAddedEvent(qim,i);
QCoreApplication::postEvent(gui, iae);
or detach cvimRGB->data and let the cleanupFunction delete the buffer
on another note there is no need to use std::shared_ptr<QImage> as QImage will not copy the underlying data unless needed, This is known in Qt as implicit data sharing
to call the gui you can provide a Q_INVOKABLE method (or just a slot) in gui and use QMetaObject::invokeMethod(gui, "imageUpdated", Q_ARG(QImage, qim));