Fl_Window subclass doesn't work - c++

As titled above, i'm trying to get an extremely simple FLTK 1.3.3 application working.
But, even with only a simple Fl_Window and 1 Fl_Button, nothing seems to work. Can anyone help?
class MainEditorWindow : public Fl_Window
{
public:
MainEditorWindow(int _width, int _height, std::string _title);
~MainEditorWindow();
virtual void draw();
virtual int handle(int _event);
private:
Fl_Button* m_btnExit;
};
And here is the Implementation
MainEditorWindow::~MainEditorWindow()
{
}
int MainEditorWindow::handle(int _event)
{
return 1;
}
void MainEditorWindow::draw()
{
m_btnExit->redraw();
}
MainEditorWindow::MainEditorWindow(int _width, int _height, std::string _title) : Fl_Window(_width, _height, _title.c_str())
{
this->begin();
m_btnExit = new Fl_Button(0, 0, 40, 40, "EXIT");
m_btnExit->color(FL_RED);
this->color(FL_WHITE);
this->end();
}
But when simply running the application like this:
int main(int argc, char** argv)
{
MainEditorWindow* mw = new MainEditorWindow(800, 600, "SHIP Editor");
mw->show(argc,argv);
return Fl::run();
}
The window shows up fine, its resizable movable etc, the draw() - function is being called and all that. But the window itself is just blank. It simply shows nothing, especially not the Fl_Button. Can anybody tell me why this occurs? As far as i can tell, there should be nothing particularily wrong with my code.

You need to call Fl_Window::draw()
void MainEditorWindow::draw()
{
m_btnExit->redraw();
Fl_Window::draw();
}
And maybe you want the button is clickable too
int MainEditorWindow::handle(int _event)
{
//return 1;
return(Fl_Window::handle(_event));
}

Try this in your MainEditorWindow constructor:
MainEditorWindow(int _width, int _height, const std::string& _title)
: Fl_Window(_width, _height, _title.c_str()) {
// begin grouped GUI object creation
Fl_Group::begin();
// alter x,y coords of button as necessary
m_btnExit = new Fl_Button(0,0,40,40,"EXIT");
m_btnExit->color(FL_RED);
// end grouped GUI object creation
Fl_Group::end();
// defines resizable widget for group
Fl_Group::resizable(this);
this->color(FL_WHITE);
// display window
Fl_Window::show();
}
Then in main:
int main(int argc, char** argv) {
MainEditorWindow mw(800, 600, "SHIP Editor");
return Fl::run();
}
Here we have added the button to a group and then invoked Fl_Window::show() inside the constructor to display it.
Note there is no need to make mw a pointer to MainEditorWindow in main.

Related

GTKmm popover menu items not highlighting when used with treeview

Good afternoon,
I'm trying to integrate a popover context menu to a treeview widget in GTKmm 4.
I've been successful in getting the menu to be displayed and for the respective actions to be called when clicking on the context menu options, however, I'm finding that the menu items are not being highlighted when the mouse hovers over them.
A GIF showing what I'm seeing is here:
If however, using the same code, I attach the menu and action group to another widget (such as a button or the window itself), all works as expected and the options are highlighted correctly.
Below is code for a minimal reproducible example.
Could someone help as I'm going round in circles with this??
#include <gtkmm.h>
class Window : public Gtk::Window {
public:
Window() {
list_store_ = Gtk::ListStore::create(model_);
auto row = *(list_store_->append());
row[model_.id] = 1;
row[model_.name] = "Example 1";
row = *(list_store_->append());
row[model_.id] = 2;
row[model_.name] = "Example 2";
treeview_.set_hexpand(true);
treeview_.set_vexpand(true);
treeview_.set_model(list_store_);
treeview_.append_column("ID", model_.id);
treeview_.append_column("Name", model_.name);
Glib::RefPtr<Gio::Menu> gmenu = Gio::Menu::create();
gmenu->append("_Edit", "popup.edit");
gmenu->append("_Remove", "popup.remove");
menu_.set_parent(treeview_);
menu_.set_menu_model(gmenu);
menu_.set_has_arrow(false);
Glib::RefPtr<Gio::SimpleActionGroup> action_group = Gio::SimpleActionGroup::create();
action_group->add_action("edit", sigc::mem_fun(*this, &Window::on_popup_edit));
action_group->add_action("remove", sigc::mem_fun(*this, &Window::on_popup_remove));
treeview_.insert_action_group("popup", action_group);
Glib::RefPtr<Gtk::GestureClick> gesture = Gtk::GestureClick::create();
gesture->set_button(GDK_BUTTON_SECONDARY);
gesture->signal_pressed().connect(sigc::mem_fun(*this, &Window::on_popup_button_pressed));
treeview_.add_controller(gesture);
set_child(treeview_);
}
~Window() override {
}
private:
class ExampleModel : public Gtk::TreeModel::ColumnRecord {
public:
ExampleModel() {
add(id);
add(name);
}
Gtk::TreeModelColumn<int> id;
Gtk::TreeModelColumn<Glib::ustring> name;
};
void on_popup_button_pressed(int, double x, double y) {
int cx, cy;
treeview_.convert_widget_to_bin_window_coords(x, y, cx, cy);
Gtk::TreeModel::Path path;
treeview_.get_path_at_pos(cx, cy, path);
if (!path) {
return;
}
const Gdk::Rectangle rect(x, y, 1, 1);
menu_.set_pointing_to(rect);
menu_.popup();
}
void on_popup_edit() { /* Implementation here */ }
void on_popup_remove() { /* Implementation here */ }
Gtk::TreeView treeview_;
ExampleModel model_;
Glib::RefPtr<Gtk::ListStore> list_store_;
Gtk::PopoverMenu menu_;
};
int main(int argc, char** argv) {
auto app = Gtk::Application::create("com.example.treeview");
return app->make_window_and_run<Window>(argc, argv);
}
Okay, so I recently had time to come back to this project.
This time I thought I'd attempt to re-write it in Rust using the gtk4-rs crate and see if the same happens and it does!
I've managed to work around this issue by wrapping the TreeView inside of a ScrolledWindow and then setting up the menu against the ScrolledView instead of the TreeView.
Inside the on_popup_button_pressed function, I'm still able to determine the path/item that was clicked.
Updated code (untested though - as the project is now written in Rust instead) is below:
#include <gtkmm.h>
class Window : public Gtk::Window {
public:
Window() {
list_store_ = Gtk::ListStore::create(model_);
auto row = *(list_store_->append());
row[model_.id] = 1;
row[model_.name] = "Example 1";
row = *(list_store_->append());
row[model_.id] = 2;
row[model_.name] = "Example 2";
treeview_.set_hexpand(true);
treeview_.set_vexpand(true);
treeview_.set_model(list_store_);
treeview_.append_column("ID", model_.id);
treeview_.append_column("Name", model_.name);
scrolled_window_.set_child(treeview_);
Glib::RefPtr<Gio::Menu> gmenu = Gio::Menu::create();
gmenu->append("_Edit", "popup.edit");
gmenu->append("_Remove", "popup.remove");
menu_.set_parent(scrolled_window_);
menu_.set_menu_model(gmenu);
menu_.set_has_arrow(false);
Glib::RefPtr<Gio::SimpleActionGroup> action_group = Gio::SimpleActionGroup::create();
action_group->add_action("edit", sigc::mem_fun(*this, &Window::on_popup_edit));
action_group->add_action("remove", sigc::mem_fun(*this, &Window::on_popup_remove));
scrolled_window.insert_action_group("popup", action_group);
Glib::RefPtr<Gtk::GestureClick> gesture = Gtk::GestureClick::create();
gesture->set_button(GDK_BUTTON_SECONDARY);
gesture->signal_pressed().connect(sigc::mem_fun(*this, &Window::on_popup_button_pressed));
scrolled_window_.add_controller(gesture);
set_child(scrolled_window_);
}
~Window() override {
}
private:
class ExampleModel : public Gtk::TreeModel::ColumnRecord {
public:
ExampleModel() {
add(id);
add(name);
}
Gtk::TreeModelColumn<int> id;
Gtk::TreeModelColumn<Glib::ustring> name;
};
void on_popup_button_pressed(int, double x, double y) {
int cx, cy;
treeview_.convert_widget_to_bin_window_coords(x, y, cx, cy);
Gtk::TreeModel::Path path;
treeview_.get_path_at_pos(cx, cy, path);
if (!path) {
return;
}
const Gdk::Rectangle rect(x, y, 1, 1);
menu_.set_pointing_to(rect);
menu_.popup();
}
void on_popup_edit() { /* Implementation here */ }
void on_popup_remove() { /* Implementation here */ }
Gtk::TreeView treeview_;
Gtk::ScrolledWindow scrolled_window_;
ExampleModel model_;
Glib::RefPtr<Gtk::ListStore> list_store_;
Gtk::PopoverMenu menu_;
};
int main(int argc, char** argv) {
auto app = Gtk::Application::create("com.example.treeview");
return app->make_window_and_run<Window>(argc, argv);
}

How to make a point appear using fltk?

After creating a window and drawing some shapes in it, I realized I cant make a point and just appear it on the window. I've searched the manual but I cant make anything out of it. Im using the fltk 1.3.0. How can I do it ?
Fltk comes with a bunch of example projects that are helpful. If you look at the line_style example you can easily reduce it to something drawing points like this:
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
class TestWindow : public Fl_Window {
void draw()
{
fl_color(255, 0, 0);
fl_begin_points();
fl_point(50, 50);
fl_point(51, 51);
fl_end_points();
}
public:
TestWindow(int w, int h, const char *l = 0)
: Fl_Window(w, h, l) {}
};
int main(int argc, char ** argv) {
Fl_Window *window = new TestWindow(200, 200);
window->end();
window->show(argc, argv);
return Fl::run();
}
But just as a word of advice, drawing single points directly onto the window is rarely the smart thing to do. Drawing into images/buffers and then displaying them is the better alternative most of the time.
edit:
here's is an example of putting the drawing code in the main function.
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
class TestWindow : public Fl_Window {
void draw() {}
public:
TestWindow(int w, int h, const char *l = 0) : Fl_Window(w, h, l) {}
};
int main(int argc, char ** argv) {
Fl_Window *window = new TestWindow(200, 200);
window->end();
window->show(argc, argv);
window->make_current();
fl_color(255, 0, 0);
fl_begin_points();
fl_point(50, 50);
fl_point(51, 51);
fl_end_points();
return Fl::run();
}
You should take notice of the disclaimer for make_current in the manual
Danger: incremental update is very hard to debug and maintain!
None of this is good practise beyond using it for simple exercises.
Based on the previous answer to this question, I found this in the documentation:
fl_begin_points()
Starts drawing a list of points.
Points are added to the list with fl_vertex()
So this is some code that shows some points (I added more to really see the points):
#include <FL/fl_draw.H>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
class Drawing : public Fl_Window {
void draw(){
fl_begin_points();
//adding cushion to points to be able to see them.
//center at 10,10
fl_vertex(9,9);
fl_vertex(9,10);
fl_vertex(9,11);
fl_vertex(10,9);
fl_vertex(10,10);
fl_vertex(10,11);
fl_vertex(11,9);
fl_vertex(11,10);
fl_vertex(11,11);
fl_end_points();
fl_color(FL_BLACK);
}
public:
Drawing(int w, int h, const char *l = 0) : Fl_Window(w, h, l){}
};
int main(int argc, char **argv){
Fl_Window *window = new Drawing(340,180);
window->end();
window->show(argc, argv);
return Fl::run();
}

How to change Gtk::Image after object creation when PixBuf is given

I am attempting to change Gtk::Image-derived object by giving it pixbuf, but i cannot figure out how to approach that.
The simple setup can be mimicked as:
#include <gtkmm.h>
#include <iostream>
class MyImage : public Gtk::Image
{
public:
void setPixBuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf);
};
void MyImage::setPixBuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
{
// How can i override the existing pixbuf here?
}
void freeImagePixelData(const guint8* data)
{
delete[] data;
}
Glib::RefPtr<Gdk::Pixbuf> generateTestImage()
{
guint8 *data = new guint8[40*40*4];
for(int i=0; i<40*40*4; )
{
data[i++] = (guint8)255; // R
data[i++] = (guint8)255; // G
data[i++] = (guint8)0; // B
data[i++] = (guint8)255; // A
}
Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_data(
data, Gdk::Colorspace::COLORSPACE_RGB, true, 8, 40, 40, 40*4, sigc::ptr_fun(&freeImagePixelData));
return pixbuf;
}
int main(int argc, char** argv)
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.almost-university.gtkmm.image.pixbuf");
Gtk::Window window;
MyImage im1;
im1.setPixBuf(generateTestImage());
window.add(im1);
window.show_all_children();
app->run(window);
return 0;
}
(Please note that this is an oversimplified version of what i am trying to figure out, i do know that i should be using Gtk::manage and not add things directly to the window without another container, this is just a mock-up).
I know that if i were to generate the image using a constructor as so:
Gtk::Image im2(generateTestImage());
window.add(im2);
then i would in fact be getting a yellow square.
Somehow i refuse to believe that one can only use pixbuf at the time of object creation. There must be a way to set the image data somehow, and i just cannot find the needed function.
To set Pixbuf in an Gtk::Image you can use Gtk::Image::set(const Glib::RefPtr< Gdk::Pixbuf >& pixbuf) method:
void MyImage::setPixBuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
{
set(pixbuf);
}

Paint device returned engine == 0, type: 1

I have seen many answers for the same Question, I have already gone through them but none them solved my problem, I am getting the error
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::end: Painter not active, aborted
I need to know, What is type : 1, and why this error showing,
My code is
iconwidget.h
class IconWigdet : public QAbstractButton
{
Q_OBJECT
QRect *iconarea;
QPainter p;
QPixmap *icon;
public:
explicit IconWigdet(QRect *rectangle,QPixmap *tempicon);
void paintEvent(QPaintEvent *);
};
iconwidget.cpp
IconWigdet::IconWigdet(QRect *rectangle,QPixmap *tempicon)
{
iconarea = new QRect();
*iconarea = *rectangle ;
icon = new QPixmap(*tempicon);
this->setGeometry(0,0,iconarea->width(),iconarea->height()+20);
}
void IconWigdet::paintEvent(QPaintEvent *)
{
qDebug() << " PaintEvent ";
p.begin(this);
p.drawText(iconarea->x()+ 10,iconarea->height()+10, "name");
p.drawPixmap ( *iconarea,*icon );
p.end();
}
groupwidget.h
class GroupWidget: public QWidget
{
Q_OBJECT
QGridLayout *groupLayout = new QGridLayout ;
QRect *rect = new QRect( 0, 0, 100, 100);
QPixmap *pimap = new QPixmap("../widgeticon/icons/ball.png");
IconWigdet *icon = new IconWigdet(rect,pimap);
public:
GroupWidget();
};
groupwidget.cpp
GroupWidget::GroupWidget()
{
groupLayout->addWidget(icon, 0, 1, 1, 1, 0);
this->setLayout(groupLayout);
icon->show();
QPaintEvent *e;
icon->paintEvent(e);
}
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GroupWidget *Gw = new GroupWidget;
Gw->show();
return a.exec();
}
and the iconwidget class will work perfectly if the main function changed to
int main(int argc, char *argv[])
{
QApplication a(argc, argv);;
QRect *rect = new QRect( 0, 0, 100, 100);
QPixmap *pimap = new QPixmap("../widgeticon/icons/ball.png");
IconWigdet *Iw = new IconWigdet(rect,pimap);
Iw->show();
return a.exec();
}
that means, If we use iconwidget class object in main function it is working, but it is not working when we do the same in groupwidget class,
Thanks in advance
You're calling IconWigdet::paintEvent directly. This is not allowed. Instead of calling it directly, call QWidget::update or QWidget::repaint.
GroupWidget::GroupWidget()
{
groupLayout->addWidget(icon, 0, 1, 1, 1, 0);
this->setLayout(groupLayout);
icon->show();
// QPaintEvent *e;
// icon->paintEvent(e); this is not allowed
icon->update(); // do this instead
}
Though I don't see why would you call anything there. Just calling Icon->show(); should be enough. Qt will automatically schedule a paint event.
Try this instead of your constructor
GroupWidget::GroupWidget()
{
groupLayout->addWidget(icon, 0, 1, 1, 1, 0);
this->setLayout(groupLayout);
setMinimumSize(100,100);
setMaximumSize(200,200);
icon->show();
}
This will work,

Segfault when creating smartpointer on CairoContext

I got some problems when creating a Cairo::RefPtr on a Cairo-Context.
I really can't imagine why this segfaults, except the pointer ist pointing on something completely wrong.
This is my code.
int main(int argc, char * argv[])
{
Gtk::Main kit(argc, argv);
Gtk::Window window;
Gtk::DrawingArea drawarea;
window.add(drawarea);
Cairo::RefPtr<Cairo::Context> ccontext = drawarea.get_window()->create_cairo_context();
Gtk::Allocation allocation = drawarea.get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
ccontext->set_source_rgb(1.0, 0.0, 0.0);
ccontext->set_line_width(2.0);
ccontext->move_to(0,0);
ccontext->line_to(width, height);
Gtk::Main::run(window);
}
And this is what GDB says:
Starting program: /home/marian/Desktop/C++/Langton/Langton [Thread
debugging using libthread_db enabled]
Program received signal SIGSEGV, Segmentation fault. 0xb7be852e in
Gdk::Window::create_cairo_context() () from /usr/lib/libgdkmm-3.0.so.1
I compiled this with gcc (GCC) 4.6.1 20110819 (prerelease).
Thanks in advance
Gtk::Widget::get_window() returns a null Glib::RefPtr, since the widget has not been realized just yet.
Based on the GtkDrawingArea documentation, you need to hook onto the "draw" signal to handle drawing, where your Cairo context is already created and handed to you. Going back to the Gtkmm reference, you would use Gtk::Widget::signal_draw() to hook onto that, or you could overload the virtual on_draw() function to handle your drawing.
Additionally, you also need to call .show() on each widget, i.e. your DrawingArea and your Window, and call ccontext->stroke() to get the line actually drawn.
The result would look something like:
#include <gtkmm.h>
bool draw (const Cairo::RefPtr<Cairo::Context> &ccontext, Gtk::DrawingArea *drawarea)
{
Gtk::Allocation allocation = drawarea->get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
ccontext->set_source_rgb(1.0, 0.0, 0.0);
ccontext->set_line_width(2.0);
ccontext->move_to(0,0);
ccontext->line_to(width, height);
ccontext->stroke ();
return true;
}
int main(int argc, char * argv[])
{
Gtk::Main kit(argc, argv);
Gtk::Window window;
Gtk::DrawingArea drawarea;
drawarea.signal_draw ().connect (sigc::bind (sigc::ptr_fun (&draw),
&drawarea));
window.add(drawarea);
window.show_all ();
Gtk::Main::run(window);
return 0;
}
or alternatively:
#include <gtkmm.h>
class LineBox : public Gtk::DrawingArea
{
protected:
virtual bool on_draw (const Cairo::RefPtr<Cairo::Context> &ccontext);
};
bool LineBox::on_draw (const Cairo::RefPtr<Cairo::Context> &ccontext)
{
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
ccontext->set_source_rgb(1.0, 0.0, 0.0);
ccontext->set_line_width(2.0);
ccontext->move_to(0,0);
ccontext->line_to(width, height);
ccontext->stroke ();
return true;
}
int main(int argc, char * argv[])
{
Gtk::Main kit(argc, argv);
Gtk::Window window;
LineBox drawarea;
window.add(drawarea);
window.show_all ();
Gtk::Main::run(window);
return 0;
}