// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt /* This is an example illustrating the use of the gui api from the dlib C++ Library. This is a pretty simple example. It makes a window with a user defined widget (a draggable colored box) and a button. You can drag the box around or click the button which increments a counter. */ #include #include #include using namespace std; using namespace dlib; // ---------------------------------------------------------------------------- class color_box : public draggable { /* Here I am defining a custom drawable widget that is a colored box that you can drag around on the screen. draggable is a special kind of drawable object that, as the name implies, is draggable by the user via the mouse. To make my color_box draggable all I need to do is inherit from draggable. */ unsigned char red, green,blue; public: color_box ( drawable_window& w, rectangle area, unsigned char red_, unsigned char green_, unsigned char blue_ ) : draggable(w), red(red_), green(green_), blue(blue_) { rect = area; set_draggable_area(rectangle(10,10,400,400)); // Whenever you make your own drawable widget (or inherit from any drawable widget // or interface such as draggable) you have to remember to call this function to // enable the events. The idea here is that you can perform whatever setup you // need to do to get your object into a valid state without needing to worry about // event handlers triggering before you are ready. enable_events(); } ~color_box ( ) { // Disable all further events for this drawable object. We have to do this // because we don't want any events (like draw()) coming to this object while or // after it has been destructed. disable_events(); // Tell the parent window to redraw its area that previously contained this // drawable object. parent.invalidate_rectangle(rect); } private: void draw ( const canvas& c ) const { // The canvas is an object that represents a part of the parent window // that needs to be redrawn. // The first thing I usually do is check if the draw call is for part // of the window that overlaps with my widget. We don't have to do this // but it is usually good to do as a speed hack. Also, the reason // I don't have it set to only give you draw calls when it does indeed // overlap is because you might want to do some drawing outside of your // widget's rectangle. But usually you don't want to do that :) rectangle area = c.intersect(rect); if (area.is_empty() == true) return; // This simple widget is just going to draw a box on the screen. fill_rect(c,rect,rgb_pixel(red,green,blue)); } }; // ---------------------------------------------------------------------------- class win : public drawable_window { /* Here I am going to define our window. In general, you can define as many window types as you like and make as many instances of them as you want. In this example I am only making one though. */ public: win( ) : // All widgets take their parent window as an argument to their constructor. c(*this), b(*this), cb(*this,rectangle(100,100,200,200),0,0,255), // the color_box will be blue and 101 pixels wide and tall mbar(*this) { // tell our button to put itself at the position (10,60). b.set_pos(10,60); b.set_name("button"); // lets put the label 5 pixels below the button c.set_pos(b.left(),b.bottom()+5); // set which function should get called when the button gets clicked. In this case we want // the on_button_clicked member to be called on *this. b.set_click_handler(*this,&win::on_button_clicked); // Alternatively, if you have a compiler which supports the lambda functions from the // new C++ standard then you can use a lambda function instead of telling the click // handler to call one of the member functions. So for example, you could do this // instead (uncomment the code if you have C++0x support): /* b.set_click_handler([&](){ ++counter; ostringstream sout; sout << "Counter: " << counter; c.set_text(sout.str()); }); */ // In general, all the functions which register events can take either member // functions or lambda functions. // Lets also make a simple menu bar. // First we say how many menus we want in our menu bar. In this example we only want 1. mbar.set_number_of_menus(1); // Now we set the name of our menu. The 'M' means that the M in Menu will be underlined // and the user will be able to select it by hitting alt+M mbar.set_menu_name(0,"Menu",'M'); // Now we add some items to the menu. Note that items in a menu are listed in the // order in which they were added. // First lets make a menu item that does the same thing as our button does when it is clicked. // Again, the 'C' means the C in Click is underlined in the menu. mbar.menu(0).add_menu_item(menu_item_text("Click Button!",*this,&win::on_button_clicked,'C')); // lets add a separator (i.e. a horizontal separating line) to the menu mbar.menu(0).add_menu_item(menu_item_separator()); // Now lets make a menu item that calls show_about when the user selects it. mbar.menu(0).add_menu_item(menu_item_text("About",*this,&win::show_about,'A')); // set the size of this window set_size(430,380); counter = 0; set_title("dlib gui example"); show(); } ~win( ) { // You should always call close_window() in the destructor of window // objects to ensure that no events will be sent to this window while // it is being destructed. close_window(); } private: void on_button_clicked ( ) { // when someone clicks our button it will increment the counter and // display it in our label c. ++counter; ostringstream sout; sout << "counter: " << counter; c.set_text(sout.str()); } void show_about( ) { message_box("About","This is a dlib gui example program"); } unsigned long counter; label c; button b; color_box cb; menu_bar mbar; }; // ---------------------------------------------------------------------------- int main() { // create our window win my_window; // wait until the user closes this window before we let the program // terminate. my_window.wait_until_closed(); return 0; } // ---------------------------------------------------------------------------- // Normally, if you built this application on MS Windows in Visual Studio you // would see a black console window pop up when you ran it. The following // #pragma directives tell Visual Studio to not include a console window along // with your application. However, if you prefer to have the console pop up as // well then simply remove these #pragma statements. #ifdef _MSC_VER # pragma comment( linker, "/entry:mainCRTStartup" ) # pragma comment( linker, "/SUBSYSTEM:WINDOWS" ) #endif // ----------------------------------------------------------------------------