Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Implementing a preferences page, coding GUIs with ATL/WTL (Read 11932 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Implementing a preferences page, coding GUIs with ATL/WTL

Oh god, I've been going through foosions general component tutorial and the windowing part is killing me. Is all that code really necessary? My component I'm going to develop is only going to need a settings dialog (I'm skipping columns UI for now), that only need like 3-4 static controls,and my thoughts are this:

a ) Do I really need to sit down and understand all this ATL/WTL stuff? I've always avoided GUI programming in C++ to all costs, and now I really understand why.

b ) Can I maybe do the dialog in the Visual Editor in VS2008 embed it as an resource and use it? If so, how?

c ) Since my dialog is going to be very simple, how about creating a small class myself that interacts with WinAPI directly? I guess I could loan foosions wrapper, but I don't really get everything it does and contains and using things I don't even understand why it works is kinda useless.

d ) Can MFC help me in this?

I know I sound like a total idiot, but this whole GUI programming in C++ truly isn't my field. I've grasped so much within the fb2k sdk during the last days and I would hate getting stopped by my lack of experience in GUI programming.


Thanks
I just like listening to music

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #1
ATL/WTL simplifies GUI programming a lot.
For a settings dialog, you can indeed create a dialog with the resource editor.

Here is a simple example of a preferences page implementation with a single checkbox whose state is read from and written to a configuration variable:

Code: [Select]
static const GUID guid_some_setting;
static cfg_bool g_some_setting(guid_some_setting, false);

static const GUID guid_my_preferences_page;

class my_preferences_page : public preferences_page, public ATL::CAxDialogImpl<my_preferences_page>
{
public:
    // preferences_page
    HWND create(HWND parent) { return Create(parent); }
    const char * get_name() { return "Some Name"; };
    GUID get_guid() { return guid_my_preferences_page; }
    GUID get_parent_guid();
    void reset() { g_some_setting = false; }
    bool reset_query() { return true; }

    // CAxDialogImpl
    enum { IDD = IDD_MY_PREFERENCES }; // ID of your dialog.

    BEGIN_MSG_MAP_EX(my_preferences_page)
        MSG_WM_INITDIALOG(OnInitDialog)
        COMMAND_HANDLER_EX(IDC_SOME_CHECKBOX, BN_CLICKED, OnSomeCheckBoxClicked)
    END_MSG_MAP()

    BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
    {
        // Initialize control states.
        CheckDlgButton(IDC_SOME_CHECKBOX, g_some_setting ? BST_CHECKED : BST_UNCHECKED);
        // Other controls can be accessed with GetDlgItem(ID).
        // You can also use WTL helpers like CListViewCtrl(GetDlgItem(ID)).
        // To pass UTF-8 strings to controls, use uSetDlgItemText() etc. from shared.h.
        return TRUE;
    }

    void OnSomeCheckBoxClicked(UINT uNotifyCode, int nID, CWindow wndCtl)
    {
        g_some_setting = (IsDlgButtonChecked(nID) == BST_CHECKED);
    }
};

static preferences_page_factory_t<my_preferences_page> g_my_preferences_page;

It might be possible to simplify it a bit using WTL's DDX (dialog data exchange), but I have not used that so far.

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #2
Now that's a great example, simple and clear, thanks a bunch!

I think I have everything I need now, I just confirmed the resource dialog worked, only thing I'm concerned about is that I need a message loop for the dialog, should I do this in another thread or could I somehow use ATL/WTL with it too?
I just like listening to music

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #3
The message loop for preferences pages is handled by the main preferences dialog.

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #4
Here is a simple example of a preferences page implementation with a single checkbox whose state is read from and written to a configuration variable: (...)

I'm probably stupid and ignorant, but I have some errors when I compile and/or link.

Basically, IDD_MY_PREFERENCES and IDC_SOME_CHECKBOX are undefined. I can solve this by writing something like :
#define IDD_MY_PREFERENCES 1985648
#define IDC_SOME_CHECKBOX 1985649

(numbers are totally random) but I guess it's not the right thing to do.

Furthermore, if I do that, I have a link error :
"public: virtual struct _GUID __thiscall my_preferences_page::get_parent_guid(void)" is undefined.

Where should this function be defined ? I think I link angainst every foobar2000 sdk library. SO should I define this function myself ?

Geest regards
Denis

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #5
Create a dialog with the resource editor and set its ID to IDD_MY_PREFERENCES in the properties window.
This automatically generates an entry in resource.h which you need to include.

Same with other controls and their IDs.

To define get_parent_guid(), refer to the documentation of the preferences_page base class.
The returned GUID depends on where you want your page to appear in the preferences tree.

 

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #6
Create a dialog with the resource editor and set its ID to IDD_MY_PREFERENCES in the properties window.
This automatically generates an entry in resource.h which you need to include.

Same with other controls and their IDs.

To define get_parent_guid(), refer to the documentation of the preferences_page base class.
The returned GUID depends on where you want your page to appear in the preferences tree.


Thank you Frank ! Your answer was very fast and accurate. Not only everything compiles and links now, but everything works as expected too :-)
Regards

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #7
This is just what I need, still using the advanced preferences interface for my settings.

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #8
I'm just starting with Dialog programming.
Been trying to get it going with WTL/ATL but in the end it seems easier without it.
Most example code I could find is also without WTL/ATL.

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #9
Yes, WTL simplifies things a lot, but you need to actually learn how WTL works. The simplifying doesn't come for free. Depending on your project it may or may not be worth learning WTL (which does take time). But I guess every programmers should just be expected to jump head first into any new encapsulation class library.


If all you know is the good old Win32 API, WTL isn't going to help you right away.

Then again I never really liked MFC, ATL, WTL. Too much macro stuff.

Just my ramblings....

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #10
It is important to realize that WTL provides only very little abstraction on top of the Win32 API (well, really only the windowing part). It merely enables you to use this API more conveniently and more efficiently in C++. Therefore, understanding the Win32 API is a prerequisite to understanding WTL.

Implementing a preferences page, coding GUIs with ATL/WTL

Reply #11
Hello everybody. I am implementing preferences page for my plugin, and I can't understand what shoud I return from "instantiate" method... In all examples that I saw ATL is used (or something else, I'm not familiar with those libraries) and I have no clue how it works. But I know WinAPI quite well, so I would like to implement preferences dialog by myself using only win api...
Please help me. Here is problem code:
Code: [Select]
#include "..\SDK\foobar2000.h"

class preferences_page_handler: public preferences_page_v3
{
    const char* get_name()
    {
        return "Deskband Controls";
    }

    GUID get_guid()
    {
        static const GUID g = { 0x5064d3a8, 0xf765, 0x4d85, { 0x8e, 0x45, 0x56, 0x4a, 0x3d, 0xd2, 0x77, 0x44 } };
        return g;
    }

    GUID get_parent_guid()
    {
        return guid_display;
    }

    preferences_page_instance::ptr instantiate(HWND parent, preferences_page_callback::ptr callback)
    {
        return ? // What should I return here?
    }
};

static preferences_page_factory_t<preferences_page_handler> foo_preferences_page_factory;


Implementing a preferences page, coding GUIs with ATL/WTL

Reply #12
You should return a pointer (wrapped in a service_ptr_t) to your implementation of the preferences_page_instance service interface.
Code: [Select]
return new service_impl_t<my_preference_page_instance>(parent, callback);
Then, in the constructor you can call CreateWindow (and throw an exception if that fails).