Hi @ all,
I need help :-(

How can I get the data from a listbox?

Here is a example, what I am searching for:

#include <string.h>
#include <vector>
#include <windows.h>
#include <nana>
#include <nana>
#include <nana>
#include <nana>
#include <nana>

// namespaces
    using namespace std;
    using namespace nana;

// --------------------- create GUI ----------------------
    // create window
        form fm(API::make_center(480,350),appear::decorate<appear::minimize>());

    // create widgets
        listbox lbTest  (fm, rectangle( 10,  10, 460, 180));
        label txtDebugA (fm, rectangle( 10, 210, 460,  20));
        label txtDebugB (fm, rectangle( 10, 240, 460,  20));
        label txtDebugC (fm, rectangle( 10, 270, 460,  20));
        button btExit   (fm, rectangle(180, 300, 120,  30));

    // global variables
        struct data { string a, b, c; };
        vector<data> lbData;
        data lastSelect = {"","",""};

int main() {
    string a,b,c;
    int i,j;

    fm.caption("Listbox test");

    // listbox test
        lbTest.append_header("column a", 145);
        lbTest.append_header("column b", 145);
        lbTest.append_header("column c", 145);
        lbTest.auto_draw(false);
        // fill the listbox...
            for (i = 0 ; i < 10 ; i++) {
                if (!(i % 2))
                    {a = "section "; a += char(i/2 + 48);}
                b = "b"; b += char(i + 48);
                c = "c"; c += char(i + 48);
                lbTest.at(0).append({a,b,c});
            }
        lbTest.auto_draw(true);
        lbTest.events().selected([fm](const arg_listbox& arg) {
            // works fine, but only with column 0
                arg.item.resolve_to(lastSelect.a);

            // does not work ...
                // arg[1].item.resolve_to(lastSelect.b);
                // arg.item[1].resolve_to(lastSelect.b);
                // arg.at(1).resolve_to(lastSelect.b);
                // lbTest.selected().at(1).resolve_to(lastSelect.b);
                // arg.item.at(1).resolve_to(lastSelect.b);

            // show the result
            txtDebugA.caption("lastSelect.a :   " + lastSelect.a);
            txtDebugB.caption("lastSelect.b :   " + lastSelect.b);
            txtDebugC.caption("lastSelect.c :   " + lastSelect.c);
        });

    // button exit
        btExit.caption("Exit");
        btExit.events().click(API::exit_all);
        btExit.events().key_char([fm](const arg_keyboard& arg) {
            if (arg.key == keyboard::enter) API::exit_all(); });

    fm.show();
    exec();
}

5ba12c4eb6359.jpg

Hi @ all, I need help :-( How can I get the data from a listbox? Here is a example, what I am searching for: ```` #include <string.h> #include <vector> #include <windows.h> #include <nana> #include <nana> #include <nana> #include <nana> #include <nana> // namespaces using namespace std; using namespace nana; // --------------------- create GUI ---------------------- // create window form fm(API::make_center(480,350),appear::decorate<appear::minimize>()); // create widgets listbox lbTest (fm, rectangle( 10, 10, 460, 180)); label txtDebugA (fm, rectangle( 10, 210, 460, 20)); label txtDebugB (fm, rectangle( 10, 240, 460, 20)); label txtDebugC (fm, rectangle( 10, 270, 460, 20)); button btExit (fm, rectangle(180, 300, 120, 30)); // global variables struct data { string a, b, c; }; vector<data> lbData; data lastSelect = {"","",""}; int main() { string a,b,c; int i,j; fm.caption("Listbox test"); // listbox test lbTest.append_header("column a", 145); lbTest.append_header("column b", 145); lbTest.append_header("column c", 145); lbTest.auto_draw(false); // fill the listbox... for (i = 0 ; i < 10 ; i++) { if (!(i % 2)) {a = "section "; a += char(i/2 + 48);} b = "b"; b += char(i + 48); c = "c"; c += char(i + 48); lbTest.at(0).append({a,b,c}); } lbTest.auto_draw(true); lbTest.events().selected([fm](const arg_listbox& arg) { // works fine, but only with column 0 arg.item.resolve_to(lastSelect.a); // does not work ... // arg[1].item.resolve_to(lastSelect.b); // arg.item[1].resolve_to(lastSelect.b); // arg.at(1).resolve_to(lastSelect.b); // lbTest.selected().at(1).resolve_to(lastSelect.b); // arg.item.at(1).resolve_to(lastSelect.b); // show the result txtDebugA.caption("lastSelect.a : " + lastSelect.a); txtDebugB.caption("lastSelect.b : " + lastSelect.b); txtDebugC.caption("lastSelect.c : " + lastSelect.c); }); // button exit btExit.caption("Exit"); btExit.events().click(API::exit_all); btExit.events().key_char([fm](const arg_keyboard& arg) { if (arg.key == keyboard::enter) API::exit_all(); }); fm.show(); exec(); } ```` ![5ba12c4eb6359.jpg](serve/attachment&path=5ba12c4eb6359.jpg)
edited Sep 18 '18 at 6:55 pm

I'm not sure how item_proxy::resolve_to is supposed to be used, but you can get the column text like this:

lastSelect.a = arg.item.text(0);
lastSelect.b = arg.item.text(1);
lastSelect.c = arg.item.text(2);

EDIT:

After looking at this example, I was able to make your code work with resolve_to (and I also had to make some other modifications to make it compilable):

#include <nana/gui/wvl.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/listbox.hpp>
#include <nana/gui/widgets/label.hpp>

#include <string.h>
#include <vector>
#include <windows.h>

using namespace nana;
using std::string;
using std::vector;

// global variables
struct data { string a, b, c; };
vector<data> lbData;
data lastSelect = {"","",""};

nana::listbox::iresolver& operator >> (nana::listbox::iresolver &ires, data &d)
{
    ires >> d.a;
    ires >> d.b;
    ires >> d.c;
    return ires;
}

int main() {
    string a, b, c;
    int i, j;

    // --------------------- create GUI ----------------------
    // create window
    form fm(API::make_center(480, 350), appear::decorate<appear::minimize>());

    // create widgets
    listbox lbTest(fm, rectangle(10, 10, 460, 180));
    label txtDebugA(fm, rectangle(10, 210, 460, 20));
    label txtDebugB(fm, rectangle(10, 240, 460, 20));
    label txtDebugC(fm, rectangle(10, 270, 460, 20));
    button btExit(fm, rectangle(180, 300, 120, 30));
    fm.caption("Listbox test");

    // listbox test
    lbTest.append_header("column a", 145);
    lbTest.append_header("column b", 145);
    lbTest.append_header("column c", 145);
    lbTest.auto_draw(false);
    // fill the listbox...
    for(i = 0; i < 10; i++) {
        if(!(i % 2))
        {
            a = "section "; a += char(i/2 + 48);
        }
        b = "b"; b += char(i + 48);
        c = "c"; c += char(i + 48);
        lbTest.at(0).append({a,b,c});
    }
    lbTest.auto_draw(true);
    lbTest.events().selected([&](const arg_listbox& arg)
    {
        arg.item.resolve_to(lastSelect);
        // show the resutl
        txtDebugA.caption("lastSelect.a :   " + lastSelect.a);
        txtDebugB.caption("lastSelect.b :   " + lastSelect.b);
        txtDebugC.caption("lastSelect.c :   " + lastSelect.c);
    });

    // button exit
    btExit.caption("Exit");
    btExit.events().click(API::exit_all);
    btExit.events().key_char([fm](const arg_keyboard& arg) {
        if(arg.key == keyboard::enter) API::exit_all(); });

    fm.show();
    exec();
}
I'm not sure how `item_proxy::resolve_to` is supposed to be used, but you can get the column text like this: ```` lastSelect.a = arg.item.text(0); lastSelect.b = arg.item.text(1); lastSelect.c = arg.item.text(2); ```` EDIT: After looking at [this example](http://qpcr4vir.github.io/nana-doxy/html/d8/de2/listbox__resolver_8cpp-example.html), I was able to make your code work with `resolve_to` (and I also had to make some other modifications to make it compilable): ```` #include <nana/gui/wvl.hpp> #include <nana/gui/widgets/button.hpp> #include <nana/gui/widgets/listbox.hpp> #include <nana/gui/widgets/label.hpp> #include <string.h> #include <vector> #include <windows.h> using namespace nana; using std::string; using std::vector; // global variables struct data { string a, b, c; }; vector<data> lbData; data lastSelect = {"","",""}; nana::listbox::iresolver& operator >> (nana::listbox::iresolver &ires, data &d) { ires >> d.a; ires >> d.b; ires >> d.c; return ires; } int main() { string a, b, c; int i, j; // --------------------- create GUI ---------------------- // create window form fm(API::make_center(480, 350), appear::decorate<appear::minimize>()); // create widgets listbox lbTest(fm, rectangle(10, 10, 460, 180)); label txtDebugA(fm, rectangle(10, 210, 460, 20)); label txtDebugB(fm, rectangle(10, 240, 460, 20)); label txtDebugC(fm, rectangle(10, 270, 460, 20)); button btExit(fm, rectangle(180, 300, 120, 30)); fm.caption("Listbox test"); // listbox test lbTest.append_header("column a", 145); lbTest.append_header("column b", 145); lbTest.append_header("column c", 145); lbTest.auto_draw(false); // fill the listbox... for(i = 0; i < 10; i++) { if(!(i % 2)) { a = "section "; a += char(i/2 + 48); } b = "b"; b += char(i + 48); c = "c"; c += char(i + 48); lbTest.at(0).append({a,b,c}); } lbTest.auto_draw(true); lbTest.events().selected([&](const arg_listbox& arg) { arg.item.resolve_to(lastSelect); // show the resutl txtDebugA.caption("lastSelect.a : " + lastSelect.a); txtDebugB.caption("lastSelect.b : " + lastSelect.b); txtDebugC.caption("lastSelect.c : " + lastSelect.c); }); // button exit btExit.caption("Exit"); btExit.events().click(API::exit_all); btExit.events().key_char([fm](const arg_keyboard& arg) { if(arg.key == keyboard::enter) API::exit_all(); }); fm.show(); exec(); } ````
edited Sep 18 '18 at 11:20 pm

lastSelect.a = arg.item.text(0);
lastSelect.b = arg.item.text(1);
lastSelect.c = arg.item.text(2);

That is it :-)
Many thanks, I have spend a lot of time in this problem.
...and the result is soooo simple ;-)

> lastSelect.a = arg.item.text(0); lastSelect.b = arg.item.text(1); lastSelect.c = arg.item.text(2); That is it :-) Many thanks, I have spend a lot of time in this problem. ...and the result is soooo simple ;-)

How can i different between select and unselect?
Example:
Click on "section 1" --> lastSelect.a contains "section 1"
Unselect "section 1" (click again) --> lastSelect.a contains again "section 1" , but I want that lastSelect.a is empty.
Sorry for my bad english and "beginner-questions" smile

How can i different between select and unselect? Example: Click on "section 1" --> lastSelect.a contains "section 1" Unselect "section 1" (click again) --> lastSelect.a contains again "section 1" , but I want that lastSelect.a is empty. Sorry for my bad english and "beginner-questions" :S
if(arg.item.selected()) 
    arg.item.resolve_to(lastSelect);
else lastSelect = {};

OR

if(arg.item.selected())
{
    lastSelect.a = arg.item.text(0);
    lastSelect.b = arg.item.text(1);
    lastSelect.c = arg.item.text(2);
}
else lastSelect = {};
```` if(arg.item.selected()) arg.item.resolve_to(lastSelect); else lastSelect = {}; ```` OR ```` if(arg.item.selected()) { lastSelect.a = arg.item.text(0); lastSelect.b = arg.item.text(1); lastSelect.c = arg.item.text(2); } else lastSelect = {}; ````

Hi again :-)

I want to sort the listbox by column A, then by column B, then by column C.
The sort by column A works fine, but the rest is unsorted.

In this example script, the sort ist:

a b 2
a a 5
a a 3
b b 1
b b 7
b a 1
...

I want this result:

a a 3
a a 5
a b 2
b a 1
b b 1
b b 7

Here ist the test script:

#include <string.h>
#include <vector>
#include <windows.h>
#include <nana/gui/wvl.hpp>
#include <nana/gui/msgbox.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/listbox.hpp>

// namespaces
    using namespace std;
    using namespace nana;

// --------------------- create GUI ----------------------
    // create window
        form fm(API::make_center(480,350),appear::decorate<appear::minimize>());

    // create widgets
        listbox lbTest  (fm, rectangle( 10,  10, 460, 180));
        label txtDebugA (fm, rectangle( 10, 210, 460,  20));
        label txtDebugB (fm, rectangle( 10, 240, 460,  20));
        label txtDebugC (fm, rectangle( 10, 270, 460,  20));
        button btExit   (fm, rectangle(180, 300, 120,  30));

    // global variables
        struct data { string a, b, c; };
        vector<data> lbData;
        data lastSelect = {"","",""};

    // functions
        bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse);

int main() {
    string a,b,c;
    int i,j;

    fm.caption("Listbox test");

    // listbox test
        lbTest.append_header("column a", 145);
        lbTest.append_header("column b", 145);
        lbTest.append_header("column c", 145);
        lbTest.auto_draw(false);
        lbTest.set_sort_compare(0, sort_compare_insensitive);
        lbTest.at(0).append({"b","b","1"});
        lbTest.at(0).append({"a","b","2"});
        lbTest.at(0).append({"c","a","3"});
        lbTest.at(0).append({"d","a","4"});
        lbTest.at(0).append({"a","a","5"});
        lbTest.at(0).append({"c","a","6"});
        lbTest.at(0).append({"b","b","7"});
        lbTest.at(0).append({"d","b","8"});
        lbTest.at(0).append({"d","a","9"});
        lbTest.at(0).append({"b","a","1"});
        lbTest.at(0).append({"c","b","2"});
        lbTest.at(0).append({"a","a","3"});

        lbTest.sort_col(0);

        lbTest.auto_draw(true);
        lbTest.events().selected([fm](const arg_listbox& arg) {
            lastSelect.a = arg.item.text(0);
            lastSelect.b = arg.item.text(1);
            lastSelect.c = arg.item.text(2);

            // show the result
            txtDebugA.caption("lastSelect.a :   " + lastSelect.a);
            txtDebugB.caption("lastSelect.b :   " + lastSelect.b);
            txtDebugC.caption("lastSelect.c :   " + lastSelect.c);
        });

    // button exit
        btExit.caption("Exit");
        btExit.events().click(API::exit_all);
        btExit.events().key_char([fm](const arg_keyboard& arg) {
            if (arg.key == keyboard::enter) API::exit_all(); });

    fm.show();
    exec();
}

bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) {
    int i, zahl = 0, start = 0;
    string s1 = s_1, s2 = s_2;

    if (s1.length()) { // if string not empty...
        for (i = 0; i < s1.length(); i++) { // check every char in string...
            if ((int)s1[i] > 96 && (int)s1[i] < 123) // if char an lower case...
                s1[i] -= 32; // convert to upper case
        }
    }
    if (s2.length()) { // if string not empty...
        for (i = 0; i < s2.length(); i++) { // check every char in string...
            if ((int)s2[i] > 96 && (int)s2[i] < 123) // if char an lower case...
                s2[i] -= 32; // convert to upper case
        }
    }
return (reverse ? s1 > s2 : s1 < s2);
}
Hi again :-) I want to sort the listbox by column A, then by column B, then by column C. The sort by column A works fine, but the rest is unsorted. In this example script, the sort ist: a b 2 a a 5 a a 3 b b 1 b b 7 b a 1 ... I want this result: a a 3 a a 5 a b 2 b a 1 b b 1 b b 7 Here ist the test script: ```` #include <string.h> #include <vector> #include <windows.h> #include <nana/gui/wvl.hpp> #include <nana/gui/msgbox.hpp> #include <nana/gui/widgets/button.hpp> #include <nana/gui/widgets/label.hpp> #include <nana/gui/widgets/listbox.hpp> // namespaces using namespace std; using namespace nana; // --------------------- create GUI ---------------------- // create window form fm(API::make_center(480,350),appear::decorate<appear::minimize>()); // create widgets listbox lbTest (fm, rectangle( 10, 10, 460, 180)); label txtDebugA (fm, rectangle( 10, 210, 460, 20)); label txtDebugB (fm, rectangle( 10, 240, 460, 20)); label txtDebugC (fm, rectangle( 10, 270, 460, 20)); button btExit (fm, rectangle(180, 300, 120, 30)); // global variables struct data { string a, b, c; }; vector<data> lbData; data lastSelect = {"","",""}; // functions bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse); int main() { string a,b,c; int i,j; fm.caption("Listbox test"); // listbox test lbTest.append_header("column a", 145); lbTest.append_header("column b", 145); lbTest.append_header("column c", 145); lbTest.auto_draw(false); lbTest.set_sort_compare(0, sort_compare_insensitive); lbTest.at(0).append({"b","b","1"}); lbTest.at(0).append({"a","b","2"}); lbTest.at(0).append({"c","a","3"}); lbTest.at(0).append({"d","a","4"}); lbTest.at(0).append({"a","a","5"}); lbTest.at(0).append({"c","a","6"}); lbTest.at(0).append({"b","b","7"}); lbTest.at(0).append({"d","b","8"}); lbTest.at(0).append({"d","a","9"}); lbTest.at(0).append({"b","a","1"}); lbTest.at(0).append({"c","b","2"}); lbTest.at(0).append({"a","a","3"}); lbTest.sort_col(0); lbTest.auto_draw(true); lbTest.events().selected([fm](const arg_listbox& arg) { lastSelect.a = arg.item.text(0); lastSelect.b = arg.item.text(1); lastSelect.c = arg.item.text(2); // show the result txtDebugA.caption("lastSelect.a : " + lastSelect.a); txtDebugB.caption("lastSelect.b : " + lastSelect.b); txtDebugC.caption("lastSelect.c : " + lastSelect.c); }); // button exit btExit.caption("Exit"); btExit.events().click(API::exit_all); btExit.events().key_char([fm](const arg_keyboard& arg) { if (arg.key == keyboard::enter) API::exit_all(); }); fm.show(); exec(); } bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) { int i, zahl = 0, start = 0; string s1 = s_1, s2 = s_2; if (s1.length()) { // if string not empty... for (i = 0; i < s1.length(); i++) { // check every char in string... if ((int)s1[i] > 96 && (int)s1[i] < 123) // if char an lower case... s1[i] -= 32; // convert to upper case } } if (s2.length()) { // if string not empty... for (i = 0; i < s2.length(); i++) { // check every char in string... if ((int)s2[i] > 96 && (int)s2[i] < 123) // if char an lower case... s2[i] -= 32; // convert to upper case } } return (reverse ? s1 > s2 : s1 < s2); } ````

It seems you are only sorting by column a:

lbTest.sort_col(0);

you probably need (in this order):

lbTest.sort_col(2);
lbTest.sort_col(1);
lbTest.sort_col(0);

Also... don't put too much in global variables... specially nana::form. It make harder to predict order of instantiation and destruction.
And you may prefer to use the std::tolower instead of rewriting it.

It seems you are only sorting by column a: ```` lbTest.sort_col(0); ```` you probably need (in this order): ```` lbTest.sort_col(2); lbTest.sort_col(1); lbTest.sort_col(0); ```` Also... don't put too much in global variables... specially ```` nana::form````. It make harder to predict order of instantiation and destruction. And you may prefer to use the [std::tolower](https://en.cppreference.com/w/cpp/string/byte/tolower) instead of rewriting it.

Great smile
Thank you very much. It works perfect.

I´ve wrote the to_upper because i need a sort function with german umlauts and Numbers ("123a" before "1234a"smile
In the test script I´ve cut this to make it so simple as possible.

Here is the original sort function smile

bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) {
    int i, zahl = 0, start = 0;
    string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2);    //Macht alles Groß, außer Sonderzeichen
    string strZahl;

    // Ersetze Soderzeichen mit "normalen" Großbuchstaben
    while (i = strPos("Ä", s1)) s1.replace(i-1,2,"A");
    while (i = strPos("Ö", s1)) s1.replace(i-1,2,"O");
    while (i = strPos("Ü", s1)) s1.replace(i-1,2,"U");
    while (i = strPos("ä", s1)) s1.replace(i-1,2,"A");
    while (i = strPos("ö", s1)) s1.replace(i-1,2,"O");
    while (i = strPos("ü", s1)) s1.replace(i-1,2,"U");
    while (i = strPos("ß", s1)) s1.replace(i-1,2,"SS");
    while (i = strPos("Ä", s2)) s2.replace(i-1,2,"A");
    while (i = strPos("Ö", s2)) s2.replace(i-1,2,"O");
    while (i = strPos("Ü", s2)) s2.replace(i-1,2,"U");
    while (i = strPos("ä", s2)) s2.replace(i-1,2,"A");
    while (i = strPos("ö", s2)) s2.replace(i-1,2,"O");
    while (i = strPos("ü", s2)) s2.replace(i-1,2,"U");
    while (i = strPos("ß", s2)) s2.replace(i-1,2,"SS");

// 01234 ist größer als 45.
// Darum:
// 1. Führende Nullen entfernen
// 2. Anzahl der Stellen voranstellen
// 3. Danach kann wieder stelle für Stelle verglichen werden
// Beispiel: aus 01234 wird "41234" , aus 45 wird "245"
// ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung

    zahl = 0;
    for (i = 0 ; i < s1.length() ; i++) {
        if (s1[i] > 47 && s1[i] < 58) {
            if (!zahl) {
                    zahl = ctoi(s1[i]);
                    if (!start) start = i;  // Die if-Abfrage ist nötig, um führende Nullen zu eliminieren
            }
            else zahl = zahl * 10 + ctoi(s1[i]);
        }
        else if (zahl) { // Es war vorher eine Zahl, aber nun kommt ein Buchstabe
            strZahl = itos(zahl);
            s1 = s1.substr(0,start) + itos(strZahl.length()) + strZahl + s1.substr(i);
            start = 0;
            zahl = 0;
        }
    }
    // Das ganze nochmal für s2 ...
    zahl = 0, start = 0;
    for (i = 0 ; i < s2.length() ; i++) {
        if (s2[i] > 47 && s2[i] < 58) {
            if (!zahl) {
                    zahl = ctoi(s2[i]);
                    if (!start) start = i;  // Die if-Abfrage ist nötig, um führende Nullen zu eliminieren
            }
            else zahl = zahl * 10 + ctoi(s2[i]);
        }
        else if (zahl) { // Es war vorher eine Zahl, aber nun kommt ein Buchstabe
            strZahl = itos(zahl);
            s2 = s2.substr(0,start) + itos(strZahl.length()) + strZahl + s2.substr(i);
            start = 0;
            zahl = 0;
        }
    }
return (reverse ? s1 > s2 : s1 < s2);
}
Great :) Thank you very much. It works perfect. I´ve wrote the to_upper because i need a sort function with german umlauts and Numbers ("123a" before "1234a") In the test script I´ve cut this to make it so simple as possible. Here is the original sort function ;) ```` bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) { int i, zahl = 0, start = 0; string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2); //Macht alles Groß, außer Sonderzeichen string strZahl; // Ersetze Soderzeichen mit "normalen" Großbuchstaben while (i = strPos("Ä", s1)) s1.replace(i-1,2,"A"); while (i = strPos("Ö", s1)) s1.replace(i-1,2,"O"); while (i = strPos("Ü", s1)) s1.replace(i-1,2,"U"); while (i = strPos("ä", s1)) s1.replace(i-1,2,"A"); while (i = strPos("ö", s1)) s1.replace(i-1,2,"O"); while (i = strPos("ü", s1)) s1.replace(i-1,2,"U"); while (i = strPos("ß", s1)) s1.replace(i-1,2,"SS"); while (i = strPos("Ä", s2)) s2.replace(i-1,2,"A"); while (i = strPos("Ö", s2)) s2.replace(i-1,2,"O"); while (i = strPos("Ü", s2)) s2.replace(i-1,2,"U"); while (i = strPos("ä", s2)) s2.replace(i-1,2,"A"); while (i = strPos("ö", s2)) s2.replace(i-1,2,"O"); while (i = strPos("ü", s2)) s2.replace(i-1,2,"U"); while (i = strPos("ß", s2)) s2.replace(i-1,2,"SS"); // 01234 ist größer als 45. // Darum: // 1. Führende Nullen entfernen // 2. Anzahl der Stellen voranstellen // 3. Danach kann wieder stelle für Stelle verglichen werden // Beispiel: aus 01234 wird "41234" , aus 45 wird "245" // ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung zahl = 0; for (i = 0 ; i < s1.length() ; i++) { if (s1[i] > 47 && s1[i] < 58) { if (!zahl) { zahl = ctoi(s1[i]); if (!start) start = i; // Die if-Abfrage ist nötig, um führende Nullen zu eliminieren } else zahl = zahl * 10 + ctoi(s1[i]); } else if (zahl) { // Es war vorher eine Zahl, aber nun kommt ein Buchstabe strZahl = itos(zahl); s1 = s1.substr(0,start) + itos(strZahl.length()) + strZahl + s1.substr(i); start = 0; zahl = 0; } } // Das ganze nochmal für s2 ... zahl = 0, start = 0; for (i = 0 ; i < s2.length() ; i++) { if (s2[i] > 47 && s2[i] < 58) { if (!zahl) { zahl = ctoi(s2[i]); if (!start) start = i; // Die if-Abfrage ist nötig, um führende Nullen zu eliminieren } else zahl = zahl * 10 + ctoi(s2[i]); } else if (zahl) { // Es war vorher eine Zahl, aber nun kommt ein Buchstabe strZahl = itos(zahl); s2 = s2.substr(0,start) + itos(strZahl.length()) + strZahl + s2.substr(i); start = 0; zahl = 0; } } return (reverse ? s1 > s2 : s1 < s2); } ````

The sort_compare_insensitive function in the script above is buggy.
When you want to use is, here is the fixed version:

bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) {
    int i, zahl = 0, start = 0, nullPos = 0;
    string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2);    //Macht alles Groß, außer Sonderzeichen
    string strZahl;

    // Ersetze Soderzeichen mit "normalen" Großbuchstaben
    while (i = strPos("Ä", s1)) s1.replace(i-1,2,"A");
    while (i = strPos("Ö", s1)) s1.replace(i-1,2,"O");
    while (i = strPos("Ü", s1)) s1.replace(i-1,2,"U");
    while (i = strPos("ä", s1)) s1.replace(i-1,2,"A");
    while (i = strPos("ö", s1)) s1.replace(i-1,2,"O");
    while (i = strPos("ü", s1)) s1.replace(i-1,2,"U");
    while (i = strPos("ß", s1)) s1.replace(i-1,2,"SS");
    while (i = strPos("Ä", s2)) s2.replace(i-1,2,"A");
    while (i = strPos("Ö", s2)) s2.replace(i-1,2,"O");
    while (i = strPos("Ü", s2)) s2.replace(i-1,2,"U");
    while (i = strPos("ä", s2)) s2.replace(i-1,2,"A");
    while (i = strPos("ö", s2)) s2.replace(i-1,2,"O");
    while (i = strPos("ü", s2)) s2.replace(i-1,2,"U");
    while (i = strPos("ß", s2)) s2.replace(i-1,2,"SS");

    // 01234 ist größer als 45.
    // Darum:
    // 1. Führende Nullen entfernen
    // 2. Anzahl der Stellen voranstellen
    // 3. Danach kann wieder stelle für Stelle verglichen werden
    // Beispiel: aus 01234 wird "41234" , aus 45 wird "245"
    // ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung

    // Führende Nullen entfernen...

    for (i = 0, start = 1; nullPos = strPos("0",s1,start) ; i++) {
        // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen
        if (nullPos == s1.length()) start++;                    // Die Null ist am Ende, da soll sie bleiben.
        else if ((nullPos == 1) && (s1[1] > 47 && s1[1] < 58))  // Das erste Zeichen ist eine Null, gefolgt von einer Zahl
            s1.erase(0,1), i--;                                 // diese Null löschen
        else if (s1[nullPos-2] < 48 || s1[nullPos-2] > 57)      // Die Null kommt irgendwo ist String vor, davor ist keine Zahl
            s1.erase(nullPos-1,1), i--;                         // diese Null löschen
        else start = nullPos + 1;                               // Die Suche eine Stelle weiter hinten fortsetzen
    }
    for (i = 0, start = 1; (nullPos = strPos("0",s2,start)) && (s2.length() > i); i++) {
        // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen
        if (nullPos == s2.length()) start++;                    // Die Null ist am Ende, da soll sie bleiben.
        else if ((nullPos == 1) && (s2[1] > 47 && s2[1] < 58))  // Das erste Zeichen ist eine Null, gefolgt von einer Zahl
            s2.erase(0,1), i--;                                 // diese Null löschen
        else if (s2[nullPos-2] < 48 || s2[nullPos-2] > 57)      // Die Null kommt irgendwo ist String vor, davor ist keine Zahl
            s2.erase(nullPos-1,1), i--;                         // diese Null löschen
        else start = nullPos + 1;                               // Die Suche eine Stelle weiter hinten fortsetzen
    }

    // Anzahl der Zahlen voranstellen...
    zahl = 0;
    for (i = 0; i <= s1.length(); i++) {
        if (s1[i] > 47 && s1[i] < 58) {                         // Eine Zahl
            if (!zahl) zahl = ctoi(s1[i]);                      // Eine "neue" Zahl...
            else zahl = zahl * 10 + ctoi(s1[i]);                // Die Zahl geht weiter
        }
        else if (zahl) {                                        // Es ist keine Zahl mehr, aber es gab eine Zahl...
            strZahl = itos(zahl);                               // Die Zahl in einen String umwandeln
            strZahl = itos(strZahl.length()) + strZahl;         // Die Anzahl der Stellen voranstellen
            s1 = s1.substr(0,i+1-strZahl.length()) + strZahl + s1.substr(i); // Die Zahl ersetzen
            zahl = 0;
        }
    }
    zahl = 0;
    for (i = 0; i <= s2.length(); i++) {
        if (s2[i] > 47 && s2[i] < 58) {                         // Eine Zahl
            if (!zahl) zahl = ctoi(s2[i]);                      // Eine "neue" Zahl...
            else zahl = zahl * 10 + ctoi(s2[i]);                // Die Zahl geht weiter
        }
        else if (zahl) {                                        // Es ist keine Zahl mehr, aber es gab eine Zahl...
            strZahl = itos(zahl);                               // Die Zahl in einen String umwandeln
            strZahl = itos(strZahl.length()) + strZahl;         // Die Anzahl der Stellen voranstellen
            s2 = s2.substr(0,i+1-strZahl.length()) + strZahl + s2.substr(i); // Die Zahl ersetzen
            zahl = 0;
        }
    }
return (reverse ? s1 > s2 : s1 < s2);
}

Sorry, the commens are in wrote in german, but this function is only intesting for german people smile

...but the way to sort Numbers (01234 is behind 234) is maybe intesting for all people.

Now, I have another problem with dbl_click...
It works fine when I double click on a entry, but it works too when I double click on the header smile
The header should be ignored by double click, how can i do this?

Here is a example script:

#include <string.h>
#include <vector>
#include <windows.h>
#include <nana/gui/wvl.hpp>
#include <nana/gui/msgbox.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/listbox.hpp>

// namespaces
    using namespace std;
    using namespace nana;

// --------------------- create GUI ----------------------
    // create window
        form fm(API::make_center(480,350),appear::decorate<appear::minimize>());

    // create widgets
        listbox lbTest  (fm, rectangle( 10,  10, 460, 180));
        label txtDebugA (fm, rectangle( 10, 210, 460,  20));
        label txtDebugB (fm, rectangle( 10, 240, 460,  20));
        label txtDebugC (fm, rectangle( 10, 270, 460,  20));
        button btExit   (fm, rectangle(180, 300, 120,  30));

    // global variables
        struct data { string a, b, c; };
        vector<data> lbData;
        data lastSelect = {"","",""};

    // functions
        int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0);

int main() {
    string a,b,c;
    int i,j;

    fm.caption("Listbox test");

    // listbox test
        lbTest.append_header("column a", 145);
        lbTest.append_header("column b", 145);
        lbTest.append_header("column c", 145);
        lbTest.enable_single(true,1);
        lbTest.auto_draw(false);

        lbTest.at(0).append({"b","b","1"});
        lbTest.at(0).append({"a","b","2"});
        lbTest.at(0).append({"c","a","3"});
        lbTest.at(0).append({"d","a","4"});
        lbTest.at(0).append({"a","a","5"});
        lbTest.at(0).append({"c","a","6"});
        lbTest.at(0).append({"b","b","7"});
        lbTest.at(0).append({"d","b","8"});
        lbTest.at(0).append({"d","a","9"});
        lbTest.at(0).append({"b","a","1"});
        lbTest.at(0).append({"c","b","2"});
        lbTest.at(0).append({"a","a","3"});

        lbTest.sort_col(2);
        lbTest.sort_col(1);
        lbTest.sort_col(0);

        lbTest.auto_draw(true);
        lbTest.events().selected([fm](const arg_listbox& arg) {
            lastSelect.a = arg.item.text(0);
            lastSelect.b = arg.item.text(1);
            lastSelect.c = arg.item.text(2);

            // show the result
            txtDebugA.caption("lastSelect.a :   " + lastSelect.a);
            txtDebugB.caption("lastSelect.b :   " + lastSelect.b);
            txtDebugC.caption("lastSelect.c :   " + lastSelect.c);
        });
        lbTest.events().dbl_click([fm]() {
            mbox("double clicked on " + lastSelect.a + " / " + lastSelect.b + " / " + lastSelect.c);
        });

    // button exit
        btExit.caption("Exit");
        btExit.events().click(API::exit_all);
        btExit.events().key_char([fm](const arg_keyboard& arg) {
            if (arg.key == keyboard::enter) API::exit_all(); });

    fm.show();
    exec();
}

int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) {    // Vereinfachte Erstellung einer MessageBox
// int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) {

// MessageBox mit Nana
// mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner])
// ---- Bedeutung der Werte ----
// Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen
// Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage
// Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein
    unsigned short auswahl;
    msgbox::button_t buttons;
    switch(art) { // Buttonauswahl
        case 1: buttons = msgbox::yes_no;           break;
        case 2: buttons = msgbox::yes_no_cancel;    break;
        default: buttons = msgbox::ok;              break;
    }
    msgbox m(fenster, titel, buttons); // Die Messagebox erstellen
    m << inhalt; // Den Inhalt (Text) einfuegen
    switch(symbol) { // Ein Icon hinzufuegen
        case 1: m.icon(m.icon_information);   break;
        case 2: m.icon(m.icon_warning);       break;
        case 3: m.icon(m.icon_error);         break;
        case 4: m.icon(m.icon_question);      break;
    }
    auto response = m(); // Auf eine Auswahl warten
    switch(response) { // Die Auswahl als Integer zurueckliefern
        case m.pick_ok: auswahl = 1;   break;
        case m.pick_yes: auswahl = 2;  break;
        case m.pick_no: auswahl = 3;   break;
        default: auswahl = 0;          break;
    }
return auswahl;
}

Many thanks smile

The sort_compare_insensitive function in the script above is buggy. When you want to use is, here is the fixed version: ```` bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) { int i, zahl = 0, start = 0, nullPos = 0; string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2); //Macht alles Groß, außer Sonderzeichen string strZahl; // Ersetze Soderzeichen mit "normalen" Großbuchstaben while (i = strPos("Ä", s1)) s1.replace(i-1,2,"A"); while (i = strPos("Ö", s1)) s1.replace(i-1,2,"O"); while (i = strPos("Ü", s1)) s1.replace(i-1,2,"U"); while (i = strPos("ä", s1)) s1.replace(i-1,2,"A"); while (i = strPos("ö", s1)) s1.replace(i-1,2,"O"); while (i = strPos("ü", s1)) s1.replace(i-1,2,"U"); while (i = strPos("ß", s1)) s1.replace(i-1,2,"SS"); while (i = strPos("Ä", s2)) s2.replace(i-1,2,"A"); while (i = strPos("Ö", s2)) s2.replace(i-1,2,"O"); while (i = strPos("Ü", s2)) s2.replace(i-1,2,"U"); while (i = strPos("ä", s2)) s2.replace(i-1,2,"A"); while (i = strPos("ö", s2)) s2.replace(i-1,2,"O"); while (i = strPos("ü", s2)) s2.replace(i-1,2,"U"); while (i = strPos("ß", s2)) s2.replace(i-1,2,"SS"); // 01234 ist größer als 45. // Darum: // 1. Führende Nullen entfernen // 2. Anzahl der Stellen voranstellen // 3. Danach kann wieder stelle für Stelle verglichen werden // Beispiel: aus 01234 wird "41234" , aus 45 wird "245" // ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung // Führende Nullen entfernen... for (i = 0, start = 1; nullPos = strPos("0",s1,start) ; i++) { // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen if (nullPos == s1.length()) start++; // Die Null ist am Ende, da soll sie bleiben. else if ((nullPos == 1) && (s1[1] > 47 && s1[1] < 58)) // Das erste Zeichen ist eine Null, gefolgt von einer Zahl s1.erase(0,1), i--; // diese Null löschen else if (s1[nullPos-2] < 48 || s1[nullPos-2] > 57) // Die Null kommt irgendwo ist String vor, davor ist keine Zahl s1.erase(nullPos-1,1), i--; // diese Null löschen else start = nullPos + 1; // Die Suche eine Stelle weiter hinten fortsetzen } for (i = 0, start = 1; (nullPos = strPos("0",s2,start)) && (s2.length() > i); i++) { // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen if (nullPos == s2.length()) start++; // Die Null ist am Ende, da soll sie bleiben. else if ((nullPos == 1) && (s2[1] > 47 && s2[1] < 58)) // Das erste Zeichen ist eine Null, gefolgt von einer Zahl s2.erase(0,1), i--; // diese Null löschen else if (s2[nullPos-2] < 48 || s2[nullPos-2] > 57) // Die Null kommt irgendwo ist String vor, davor ist keine Zahl s2.erase(nullPos-1,1), i--; // diese Null löschen else start = nullPos + 1; // Die Suche eine Stelle weiter hinten fortsetzen } // Anzahl der Zahlen voranstellen... zahl = 0; for (i = 0; i <= s1.length(); i++) { if (s1[i] > 47 && s1[i] < 58) { // Eine Zahl if (!zahl) zahl = ctoi(s1[i]); // Eine "neue" Zahl... else zahl = zahl * 10 + ctoi(s1[i]); // Die Zahl geht weiter } else if (zahl) { // Es ist keine Zahl mehr, aber es gab eine Zahl... strZahl = itos(zahl); // Die Zahl in einen String umwandeln strZahl = itos(strZahl.length()) + strZahl; // Die Anzahl der Stellen voranstellen s1 = s1.substr(0,i+1-strZahl.length()) + strZahl + s1.substr(i); // Die Zahl ersetzen zahl = 0; } } zahl = 0; for (i = 0; i <= s2.length(); i++) { if (s2[i] > 47 && s2[i] < 58) { // Eine Zahl if (!zahl) zahl = ctoi(s2[i]); // Eine "neue" Zahl... else zahl = zahl * 10 + ctoi(s2[i]); // Die Zahl geht weiter } else if (zahl) { // Es ist keine Zahl mehr, aber es gab eine Zahl... strZahl = itos(zahl); // Die Zahl in einen String umwandeln strZahl = itos(strZahl.length()) + strZahl; // Die Anzahl der Stellen voranstellen s2 = s2.substr(0,i+1-strZahl.length()) + strZahl + s2.substr(i); // Die Zahl ersetzen zahl = 0; } } return (reverse ? s1 > s2 : s1 < s2); } ```` Sorry, the commens are in wrote in german, but this function is only intesting for german people ;) ...but the way to sort Numbers (01234 is behind 234) is maybe intesting for all people. Now, I have another problem with dbl_click... It works fine when I double click on a entry, but it works too when I double click on the header :S The header should be ignored by double click, how can i do this? Here is a example script: ```` #include <string.h> #include <vector> #include <windows.h> #include <nana/gui/wvl.hpp> #include <nana/gui/msgbox.hpp> #include <nana/gui/widgets/button.hpp> #include <nana/gui/widgets/label.hpp> #include <nana/gui/widgets/listbox.hpp> // namespaces using namespace std; using namespace nana; // --------------------- create GUI ---------------------- // create window form fm(API::make_center(480,350),appear::decorate<appear::minimize>()); // create widgets listbox lbTest (fm, rectangle( 10, 10, 460, 180)); label txtDebugA (fm, rectangle( 10, 210, 460, 20)); label txtDebugB (fm, rectangle( 10, 240, 460, 20)); label txtDebugC (fm, rectangle( 10, 270, 460, 20)); button btExit (fm, rectangle(180, 300, 120, 30)); // global variables struct data { string a, b, c; }; vector<data> lbData; data lastSelect = {"","",""}; // functions int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0); int main() { string a,b,c; int i,j; fm.caption("Listbox test"); // listbox test lbTest.append_header("column a", 145); lbTest.append_header("column b", 145); lbTest.append_header("column c", 145); lbTest.enable_single(true,1); lbTest.auto_draw(false); lbTest.at(0).append({"b","b","1"}); lbTest.at(0).append({"a","b","2"}); lbTest.at(0).append({"c","a","3"}); lbTest.at(0).append({"d","a","4"}); lbTest.at(0).append({"a","a","5"}); lbTest.at(0).append({"c","a","6"}); lbTest.at(0).append({"b","b","7"}); lbTest.at(0).append({"d","b","8"}); lbTest.at(0).append({"d","a","9"}); lbTest.at(0).append({"b","a","1"}); lbTest.at(0).append({"c","b","2"}); lbTest.at(0).append({"a","a","3"}); lbTest.sort_col(2); lbTest.sort_col(1); lbTest.sort_col(0); lbTest.auto_draw(true); lbTest.events().selected([fm](const arg_listbox& arg) { lastSelect.a = arg.item.text(0); lastSelect.b = arg.item.text(1); lastSelect.c = arg.item.text(2); // show the result txtDebugA.caption("lastSelect.a : " + lastSelect.a); txtDebugB.caption("lastSelect.b : " + lastSelect.b); txtDebugC.caption("lastSelect.c : " + lastSelect.c); }); lbTest.events().dbl_click([fm]() { mbox("double clicked on " + lastSelect.a + " / " + lastSelect.b + " / " + lastSelect.c); }); // button exit btExit.caption("Exit"); btExit.events().click(API::exit_all); btExit.events().key_char([fm](const arg_keyboard& arg) { if (arg.key == keyboard::enter) API::exit_all(); }); fm.show(); exec(); } int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) { // Vereinfachte Erstellung einer MessageBox // int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) { // MessageBox mit Nana // mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner]) // ---- Bedeutung der Werte ---- // Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen // Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage // Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein unsigned short auswahl; msgbox::button_t buttons; switch(art) { // Buttonauswahl case 1: buttons = msgbox::yes_no; break; case 2: buttons = msgbox::yes_no_cancel; break; default: buttons = msgbox::ok; break; } msgbox m(fenster, titel, buttons); // Die Messagebox erstellen m << inhalt; // Den Inhalt (Text) einfuegen switch(symbol) { // Ein Icon hinzufuegen case 1: m.icon(m.icon_information); break; case 2: m.icon(m.icon_warning); break; case 3: m.icon(m.icon_error); break; case 4: m.icon(m.icon_question); break; } auto response = m(); // Auf eine Auswahl warten switch(response) { // Die Auswahl als Integer zurueckliefern case m.pick_ok: auswahl = 1; break; case m.pick_yes: auswahl = 2; break; case m.pick_no: auswahl = 3; break; default: auswahl = 0; break; } return auswahl; } ```` Many thanks :)

You could do it by checking whether the mouse cursor is hovering over a list item when the event triggers:

lbTest.events().dbl_click([&lbTest](const arg_mouse &arg) {
    if(!lbTest.cast(arg.pos).empty())
        mbox("double clicked on " + lastSelect.a + " / " + lastSelect.b + " / " + lastSelect.c);
});

Edit: By the way, you shouldn't declare any widgets in the global namespace. To quote Jinhao from a previous post:

Moreover, all widgets should not be declared as a global variable. Because it is impossible to guarantee that the nana internal data/objects that are required by widget's initialization are initalized before the global variable.

Your code crashed at startup, so I had to move all the "create GUI" stuff into the main function. Here's the call stack when it crashed:

>    Nana Test.exe!nana::detail::bedrock::wd_manager() Line 104

     Nana Test.exe!nana::restrict::`anonymous namespace'::wd_manager() Line 41

     Nana Test.exe!nana::API::dev::create_window(nana::detail::window_handle_impl * owner, bool nested, const nana::rectangle & r, const nana::appearance & ap, nana::widget * wdg) Line 293

     Nana Test.exe!nana::widget_object<nana::category::root_tag,nana::drawerbase::form::trigger,nana::detail::events_root_extension,nana::widget_geometrics,void>::widget_object<nana::category::root_tag,nana::drawerbase::form::trigger,nana::detail::events_root_extension,nana::widget_geometrics,void>(nana::detail::window_handle_impl * owner, bool nested, const nana::rectangle & r, const nana::appearance & apr) Line 381

     Nana Test.exe!nana::drawerbase::form::form_base::form_base(nana::detail::window_handle_impl * owner, bool nested, const nana::rectangle & r, const nana::appearance & app) Line 37

     Nana Test.exe!nana::form::form(const nana::rectangle & r, const nana::appearance & apr) Line 79

     Nana Test.exe!`dynamic initializer for 'fm''() Line 965

     Nana Test.exe!_initterm(void(*)() * first, void(*)() * last) Line 22
You could do it by checking whether the mouse cursor is hovering over a list item when the event triggers: ```` lbTest.events().dbl_click([&lbTest](const arg_mouse &arg) { if(!lbTest.cast(arg.pos).empty()) mbox("double clicked on " + lastSelect.a + " / " + lastSelect.b + " / " + lastSelect.c); }); ```` Edit: By the way, you shouldn't declare any widgets in the global namespace. To quote Jinhao from a previous post: > Moreover, all widgets should not be declared as a global variable. Because it is impossible to guarantee that the nana internal data/objects that are required by widget's initialization are initalized before the global variable. Your code crashed at startup, so I had to move all the "create GUI" stuff into the main function. Here's the call stack when it crashed: ```` > Nana Test.exe!nana::detail::bedrock::wd_manager() Line 104 Nana Test.exe!nana::restrict::`anonymous namespace'::wd_manager() Line 41 Nana Test.exe!nana::API::dev::create_window(nana::detail::window_handle_impl * owner, bool nested, const nana::rectangle & r, const nana::appearance & ap, nana::widget * wdg) Line 293 Nana Test.exe!nana::widget_object<nana::category::root_tag,nana::drawerbase::form::trigger,nana::detail::events_root_extension,nana::widget_geometrics,void>::widget_object<nana::category::root_tag,nana::drawerbase::form::trigger,nana::detail::events_root_extension,nana::widget_geometrics,void>(nana::detail::window_handle_impl * owner, bool nested, const nana::rectangle & r, const nana::appearance & apr) Line 381 Nana Test.exe!nana::drawerbase::form::form_base::form_base(nana::detail::window_handle_impl * owner, bool nested, const nana::rectangle & r, const nana::appearance & app) Line 37 Nana Test.exe!nana::form::form(const nana::rectangle & r, const nana::appearance & apr) Line 79 Nana Test.exe!`dynamic initializer for 'fm''() Line 965 Nana Test.exe!_initterm(void(*)() * first, void(*)() * last) Line 22 ````
edited Oct 9 '18 at 12:09 pm

Thank you very much, It works perfect.

I´ve tryed to put all in the Main function, but then it does not work anymore.
I will try it again with more patience.

Thank you very much, It works perfect. I´ve tryed to put all in the Main function, but then it does not work anymore. I will try it again with more patience.

This version of your code works perfectly for me (using Visual Studio 2015):

#include <string.h>
#include <vector>
#include <windows.h>
#include <nana/gui/wvl.hpp>
#include <nana/gui/msgbox.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/widgets/listbox.hpp>

// namespaces
using namespace nana;
using std::string;
using std::vector;


// global variables
struct data { string a, b, c; };
vector<data> lbData;
data lastSelect = {"","",""};

// functions
int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0);

int main() {
    string a, b, c;
    int i, j;

    // --------------------- create GUI ----------------------
    // create window
    form fm(API::make_center(480, 350), appear::decorate<appear::minimize>());

    // create widgets
    listbox lbTest(fm, rectangle(10, 10, 460, 180));
    label txtDebugA(fm, rectangle(10, 210, 460, 20));
    label txtDebugB(fm, rectangle(10, 240, 460, 20));
    label txtDebugC(fm, rectangle(10, 270, 460, 20));
    button btExit(fm, rectangle(180, 300, 120, 30));

    fm.caption("Listbox test");

    // listbox test
    lbTest.append_header("column a", 145);
    lbTest.append_header("column b", 145);
    lbTest.append_header("column c", 145);
    lbTest.enable_single(true, 1);
    lbTest.auto_draw(false);

    lbTest.at(0).append({"b","b","1"});
    lbTest.at(0).append({"a","b","2"});
    lbTest.at(0).append({"c","a","3"});
    lbTest.at(0).append({"d","a","4"});
    lbTest.at(0).append({"a","a","5"});
    lbTest.at(0).append({"c","a","6"});
    lbTest.at(0).append({"b","b","7"});
    lbTest.at(0).append({"d","b","8"});
    lbTest.at(0).append({"d","a","9"});
    lbTest.at(0).append({"b","a","1"});
    lbTest.at(0).append({"c","b","2"});
    lbTest.at(0).append({"a","a","3"});

    lbTest.sort_col(2);
    lbTest.sort_col(1);
    lbTest.sort_col(0);

    lbTest.auto_draw(true);
    lbTest.events().selected([&](const arg_listbox& arg) {
        lastSelect.a = arg.item.text(0);
        lastSelect.b = arg.item.text(1);
        lastSelect.c = arg.item.text(2);

        // show the result
        txtDebugA.caption("lastSelect.a :   " + lastSelect.a);
        txtDebugB.caption("lastSelect.b :   " + lastSelect.b);
        txtDebugC.caption("lastSelect.c :   " + lastSelect.c);
    });
    lbTest.events().dbl_click([&lbTest](const arg_mouse &arg) {
        if(!lbTest.cast(arg.pos).empty())
            mbox("double clicked on " + lastSelect.a + " / " + lastSelect.b + " / " + lastSelect.c);
    });

    // button exit
    btExit.caption("Exit");
    btExit.events().click(API::exit_all);
    btExit.events().key_char([](const arg_keyboard& arg) {
        if(arg.key == keyboard::enter) API::exit_all(); });

    fm.show();
    exec();
}

int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) {    // Vereinfachte Erstellung einer MessageBox
                                                                                                      // int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) {

                                                                                                      // MessageBox mit Nana
                                                                                                      // mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner])
                                                                                                      // ---- Bedeutung der Werte ----
                                                                                                      // Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen
                                                                                                      // Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage
                                                                                                      // Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein
    unsigned short auswahl;
    msgbox::button_t buttons;
    switch(art) { // Buttonauswahl
    case 1: buttons = msgbox::yes_no;           break;
    case 2: buttons = msgbox::yes_no_cancel;    break;
    default: buttons = msgbox::ok;              break;
    }
    msgbox m(fenster, titel, buttons); // Die Messagebox erstellen
    m << inhalt; // Den Inhalt (Text) einfuegen
    switch(symbol) { // Ein Icon hinzufuegen
    case 1: m.icon(m.icon_information);   break;
    case 2: m.icon(m.icon_warning);       break;
    case 3: m.icon(m.icon_error);         break;
    case 4: m.icon(m.icon_question);      break;
    }
    auto response = m(); // Auf eine Auswahl warten
    switch(response) { // Die Auswahl als Integer zurueckliefern
    case m.pick_ok: auswahl = 1;   break;
    case m.pick_yes: auswahl = 2;  break;
    case m.pick_no: auswahl = 3;   break;
    default: auswahl = 0;          break;
    }
    return auswahl;
}

I had to remove using namespace std because your data was conflicting with std::data.

Also, it seems that the latest commit to nana's "develop-1.7" branch has added a hovered method to the listbox, that you could probably use instead of my solution (although I'm not sure if there would be any benefit to that).

This version of your code works perfectly for me (using Visual Studio 2015): ```` #include <string.h> #include <vector> #include <windows.h> #include <nana/gui/wvl.hpp> #include <nana/gui/msgbox.hpp> #include <nana/gui/widgets/button.hpp> #include <nana/gui/widgets/label.hpp> #include <nana/gui/widgets/listbox.hpp> // namespaces using namespace nana; using std::string; using std::vector; // global variables struct data { string a, b, c; }; vector<data> lbData; data lastSelect = {"","",""}; // functions int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0); int main() { string a, b, c; int i, j; // --------------------- create GUI ---------------------- // create window form fm(API::make_center(480, 350), appear::decorate<appear::minimize>()); // create widgets listbox lbTest(fm, rectangle(10, 10, 460, 180)); label txtDebugA(fm, rectangle(10, 210, 460, 20)); label txtDebugB(fm, rectangle(10, 240, 460, 20)); label txtDebugC(fm, rectangle(10, 270, 460, 20)); button btExit(fm, rectangle(180, 300, 120, 30)); fm.caption("Listbox test"); // listbox test lbTest.append_header("column a", 145); lbTest.append_header("column b", 145); lbTest.append_header("column c", 145); lbTest.enable_single(true, 1); lbTest.auto_draw(false); lbTest.at(0).append({"b","b","1"}); lbTest.at(0).append({"a","b","2"}); lbTest.at(0).append({"c","a","3"}); lbTest.at(0).append({"d","a","4"}); lbTest.at(0).append({"a","a","5"}); lbTest.at(0).append({"c","a","6"}); lbTest.at(0).append({"b","b","7"}); lbTest.at(0).append({"d","b","8"}); lbTest.at(0).append({"d","a","9"}); lbTest.at(0).append({"b","a","1"}); lbTest.at(0).append({"c","b","2"}); lbTest.at(0).append({"a","a","3"}); lbTest.sort_col(2); lbTest.sort_col(1); lbTest.sort_col(0); lbTest.auto_draw(true); lbTest.events().selected([&](const arg_listbox& arg) { lastSelect.a = arg.item.text(0); lastSelect.b = arg.item.text(1); lastSelect.c = arg.item.text(2); // show the result txtDebugA.caption("lastSelect.a : " + lastSelect.a); txtDebugB.caption("lastSelect.b : " + lastSelect.b); txtDebugC.caption("lastSelect.c : " + lastSelect.c); }); lbTest.events().dbl_click([&lbTest](const arg_mouse &arg) { if(!lbTest.cast(arg.pos).empty()) mbox("double clicked on " + lastSelect.a + " / " + lastSelect.b + " / " + lastSelect.c); }); // button exit btExit.caption("Exit"); btExit.events().click(API::exit_all); btExit.events().key_char([](const arg_keyboard& arg) { if(arg.key == keyboard::enter) API::exit_all(); }); fm.show(); exec(); } int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) { // Vereinfachte Erstellung einer MessageBox // int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) { // MessageBox mit Nana // mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner]) // ---- Bedeutung der Werte ---- // Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen // Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage // Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein unsigned short auswahl; msgbox::button_t buttons; switch(art) { // Buttonauswahl case 1: buttons = msgbox::yes_no; break; case 2: buttons = msgbox::yes_no_cancel; break; default: buttons = msgbox::ok; break; } msgbox m(fenster, titel, buttons); // Die Messagebox erstellen m << inhalt; // Den Inhalt (Text) einfuegen switch(symbol) { // Ein Icon hinzufuegen case 1: m.icon(m.icon_information); break; case 2: m.icon(m.icon_warning); break; case 3: m.icon(m.icon_error); break; case 4: m.icon(m.icon_question); break; } auto response = m(); // Auf eine Auswahl warten switch(response) { // Die Auswahl als Integer zurueckliefern case m.pick_ok: auswahl = 1; break; case m.pick_yes: auswahl = 2; break; case m.pick_no: auswahl = 3; break; default: auswahl = 0; break; } return auswahl; } ```` I had to remove `using namespace std` because your `data` was conflicting with `std::data`. Also, it seems that the [latest commit](https://github.com/cnjinhao/nana/commit/943a9e444d757dbdf868c4ff607bbccfb21f5485) to nana's "develop-1.7" branch has added a [hovered](https://github.com/cnjinhao/nana/blob/develop-1.7/source/gui/widgets/listbox.cpp#L5855) method to the listbox, that you could probably use instead of my solution (although I'm not sure if there would be any benefit to that).
edited Oct 9 '18 at 7:46 pm

I have replaced all [fm] by [&WidgetName], it works fine.
But I cant put this in the main:

        form fm(API::make_center(520,350),appear::decorate<appear::minimize>());

    // Steuerelemente erstellen
        label labelSuchen       (fm, rectangle( 10,  10, 200,  22));            // Label Suchen
        textbox textboxSuchen   (fm, rectangle( 10,  33, 300,  22));            // Textbox Suchen
        listbox listboxLager    (fm, rectangle( 10,  70, 500, 180));            // Listbox Lager
        button buttonNeu        (fm, rectangle( 10, 300, 120,  30));            // Button Bearbeiten
        button buttonBeenden    (fm, rectangle(150, 300, 120,  30));            // Button Beenden

        label debug (fm, rectangle(300, 300, 210,  30));

...because I need to change from functions.

My program is not completed at this moment, but I will show you, so you can understand much easier what i am working for.
Sorry for my bad english, and sorry for german comments.
Here is the program:

#include <fstream>                              // fuer Dateibehandlungen
// #include <stdlib.h>                             // fuer Zufall
#include <string.h>                             // fuer Strings
// #include <time.h>                               // fuer Zufall
#include <vector>                               // für Vektoren (dynamische Arrays)
#include <windows.h>                            // fuer Windows-Funktionen
#include<nana/gui/dragger.hpp>                  // Drag & Drop
#include <nana/gui/wvl.hpp>                     // Nana Klasswendefinition
#include <nana/gui/msgbox.hpp>                  // fuer Message-Boxen
// #include <nana/gui/timer.hpp>                   // fuer Timer
#include <nana/gui/tooltip.hpp>                 // fuer Tooltips
#include <nana/gui/widgets/button.hpp>          // fuer Buttons
// #include <nana/gui/widgets/checkbox.hpp>        // fuer Check-Boxen
// #include <nana/gui/widgets/group.hpp>           // fuer Gruppen
#include <nana/gui/widgets/label.hpp>           // fuer Label
#include <nana/gui/widgets/listbox.hpp>         // fuer Listbox
// #include <nana/gui/widgets/slider.hpp>          // fuer Slider
#include <nana/gui/widgets/textbox.hpp>         // fuer Text-Boxen



// Namespaces
    using namespace std;
    using namespace nana;

// Globale Variablen
//{
    int bgc = 0xF4F4FB;                                 // Hintergrundfarbe
    struct iniInhalt { string b, f, m; };               // Eine Struktur für den Lagerinhalt
    vector<iniInhalt> ini;                              // Eine Variable des Types iniInhalt
    iniInhalt lastSelect = {"","",""};                  // letzte Auswahl in der Listbox
    iniInhalt lastSelectBefore = {"","",""};            // vorletzte Auswahl in der Listbox (fuer Doppelklick)
//}

// Deklarationen
//{
    int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0); // Vereinfachte Erstellung einer MessageBox
    int strPos(string sNeedle, string sHaystack, int iStartPos = 1);                                // Ermittelt die Position in einem String
    string itos(unsigned long long i, unsigned short base = 10);                                    // Macht aus Zahlen Strings
    int ctoi(char c);                                                                               // Wandelt String-Zahlen in Integer-Zahlen
    string stringToUpper(string s);                                                                 // Wandelt alles in Großbuchstaben
    bool sort_compare_insensitive(const string& s1, any*, const string& s2, any*, bool reverse);    // Sortiert alphabetisch (ohne Groß-Kein-Unterscheidung)
    void inventur();                                                                                // Gibt den gesamten Lagerbestand zurück.
    void liveSuche();                                                                               // Prüft ob der Suchtext in der Listbox vorhanden ist
    void bearbeiten();                                                                              // zum bearbeiten/hinzufügen eines Eintrages
//}

// ************************************* GUI erstellen **************************************

// --------------------- Fenster und Steuerelemente erstellen (global) ----------------------
//{
    // Fenster erstellen
        form fm(API::make_center(520,350),appear::decorate<appear::minimize>());

    // Steuerelemente erstellen
        label labelSuchen       (fm, rectangle( 10,  10, 200,  22));            // Label Suchen
        textbox textboxSuchen   (fm, rectangle( 10,  33, 300,  22));            // Textbox Suchen
        listbox listboxLager    (fm, rectangle( 10,  70, 500, 180));            // Listbox Lager
        button buttonNeu        (fm, rectangle( 10, 300, 120,  30));            // Button Bearbeiten
        button buttonBeenden    (fm, rectangle(150, 300, 120,  30));            // Button Beenden

        label debug (fm, rectangle(300, 300, 210,  30));

//}

int main() {
    // Das Fenster verschiebbar machen, indem man einfach ins Fenster klickt und die Maus zieht.
    dragger dgMain;
    dgMain.target(fm);
    dgMain.trigger(fm);

    // ------------------------------------- Icon  -------------------------------------
    wstring app_path(4096, '\0');                                                   // Speichert den Pfad des ausgeführten Programms
    app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size()));     // Passt die Groesse an
    fm.icon(paint::image(app_path));                                                // Verwendet das Icon der EXE (dieses ist per Recource festgelegt)

    // ----------------------------- Variablen deklarieren -----------------------------
    string str;                                                                     // für temporaere Strings
    string lagerIni;                                                                // Lädt den gesamten Lagerbestand in die Variable

    // ------------------------- Steuerelemente "einrichten" ---------------------------

    // Fenster
        fm.caption("Store Manager v1.0");                                           // Fenstertitel
        fm.bgcolor(color_rgb(bgc));                                                 // Hintergrundfarbe

    // Label Suchen
        labelSuchen.bgcolor(color_rgb(bgc));                                        // Hintergrundfarbe
        labelSuchen.format(true);                                                   // Ermoeglicht HTML-Formatierung
        labelSuchen.caption({                                                       // Text "Comic Sans MS"
            "<size=12, bold=false, font=\"Comic Sans MS\">Suche nach:</>"});
        labelSuchen.tooltip("Wonach gesucht werden soll...");                       // Tooltip

    // Textbox Suchen
        textboxSuchen.multi_lines(false);                                           // Nur eine Zeile erlaubt
        textboxSuchen.typeface(paint::font{"Comic Sans MS", 10});                   // Schrift und Schriftgroesse
        textboxSuchen.focus();                                                      // Setzt den Focus
        textboxSuchen.events().text_changed(liveSuche);                             // Ruft die Live-Suche auf
        textboxSuchen.events().key_char([&textboxSuchen](const arg_keyboard& arg) { // Event Taste
            if (arg.key == keyboard::enter) mbox("Fehlt noch!");                    // Wenn Enter ...
            // hier sollte nun in das nächste Suchfeld gesprungen werden
        });

    //  Listbox Lager
        listboxLager.enable_single(true,1);                                         // Erlaubt nur eine Auswahl (keine Mehrfachauswahl)
        listboxLager.typeface(paint::font{"Comic Sans MS", 10});                    // Schrift und Schriftgroesse für die Listbox
        listboxLager.append_header("Bezeichnung", 180);                             // Spalte "Bezeichnung"
        listboxLager.append_header("Lagerort", 230);                                // Spalte "Lagerort"
        listboxLager.append_header("Menge", 65);                                    // Spalte "Menge"
        listboxLager.column_at(0).typeface(paint::font{"Comic Sans MS", 12});       // Schrift und Schriftgroesse für die Überschrift der Spalte 0
        listboxLager.column_at(1).typeface(paint::font{"Comic Sans MS", 12});       // Schrift und Schriftgroesse für die Überschrift der Spalte 1
        listboxLager.column_at(2).typeface(paint::font{"Comic Sans MS", 12});       // Schrift und Schriftgroesse für die Überschrift der Spalte 2
        listboxLager.sortable(true);
        listboxLager.auto_draw(false);
        listboxLager.set_sort_compare(0, sort_compare_insensitive);                 // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung
        listboxLager.set_sort_compare(1, sort_compare_insensitive);                 // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung
        listboxLager.set_sort_compare(2, sort_compare_insensitive);                 // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung
        inventur();                                                                 // Liest die Daten aus der INI-Datei
        liveSuche();                                                                // Filtert die Listbox nach dem Suchstring
        listboxLager.auto_draw(true);
        listboxLager.events().selected([&listboxLager](const arg_listbox& arg) {
            if(arg.item.selected()) {
                lastSelect = {arg.item.text(0),arg.item.text(1),arg.item.text(2)};
                if (lastSelect.b != "") lastSelectBefore = lastSelect;              // beim Doppelklick wird markiert/demarkiert
            }
            else lastSelect = {};
        });
        listboxLager.events().dbl_click([&listboxLager](const arg_mouse &arg) {     // beim Doppelklick merken wo die Maus steht
            if(!listboxLager.cast(arg.pos).empty()) {                               // Wenn die auf einen Eintrag steht...
                if (lastSelect.b == "") lastSelect = lastSelectBefore;
                bearbeiten();
            }
        });
        listboxLager.events().key_char([&listboxLager](const arg_keyboard& arg) {   // Event Taste Enter
            if ((arg.key == keyboard::enter) && (lastSelect.b != "")) bearbeiten(); // Wenn Enter bei selektierter Listbox --> ...
        });

    // Button Neu
        buttonNeu.typeface(paint::font{"Comic Sans MS", 12});                       // Schrift und Schriftgroesse
        buttonNeu.caption("Neuer Eintrag");                                         // Beschriftung des Button
        //buttonNeu.caption((wstring)charset("Neuer Eintrag"));                       // Beschriftung des Button (in UTF-8)
        buttonNeu.enable_focus_color(false);                                        // Die "Fokus-Farbe" deaktivieren
        buttonNeu.events().click([&buttonNeu]() { bearbeiten(); });                 // Event: Click LM
        buttonNeu.events().key_char([&buttonNeu](const arg_keyboard& arg) {         // Event Taste Enter
            if (arg.key == keyboard::enter) bearbeiten();                           // Wenn Enter bei focusierten Button --> ...
        });

    // Button Beenden
        buttonBeenden.typeface(paint::font{"Comic Sans MS", 12});                   // Schrift und Schriftgroesse
        buttonBeenden.caption("Beenden");                                           // Beschriftung des Button
        buttonBeenden.enable_focus_color(false);                                    // Die "Fokus-Farbe" deaktivieren
        buttonBeenden.events().click(API::exit_all);                                // Event: Click LM
        buttonBeenden.events().key_char([&buttonBeenden](const arg_keyboard& arg) { // Event Taste Enter
            if (arg.key == keyboard::enter) API::exit_all();                        // Wenn Enter bei focusierten Button --> Programm schließen
        });

    // GUI anzeigen
        fm.show();                                                                  // GUI sichtbar machen
        exec();                                                                     // Endlosschleife bis die GUI zerstoert wird (warten auf Ereignisse)
return 0;
}

int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) {    // Vereinfachte Erstellung einer MessageBox
// int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) {

// MessageBox mit Nana
// mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner])
// ---- Bedeutung der Werte ----
// Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen
// Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage
// Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein
    unsigned short auswahl;
    msgbox::button_t buttons;
    switch(art) { // Buttonauswahl
        case 1: buttons = msgbox::yes_no;           break;
        case 2: buttons = msgbox::yes_no_cancel;    break;
        default: buttons = msgbox::ok;              break;
    }
    msgbox m(fenster, titel, buttons); // Die Messagebox erstellen
    m << inhalt; // Den Inhalt (Text) einfuegen
    switch(symbol) { // Ein Icon hinzufuegen
        case 1: m.icon(m.icon_information);   break;
        case 2: m.icon(m.icon_warning);       break;
        case 3: m.icon(m.icon_error);         break;
        case 4: m.icon(m.icon_question);      break;
    }
    auto response = m(); // Auf eine Auswahl warten
    switch(response) { // Die Auswahl als Integer zurueckliefern
        case m.pick_ok: auswahl = 1;   break;
        case m.pick_yes: auswahl = 2;  break;
        case m.pick_no: auswahl = 3;   break;
        default: auswahl = 0;          break;
    }
return auswahl;
}

int strPos(string sNeedle, string sHaystack, int iStartPos) { // needs #include <string>
// search needle in haystack
    unsigned short iFoundPos = 0, j;
    // if haystack >= needle...
    if (sHaystack.length() >= sNeedle.length()) {
        // while haystack is big enough to contain the needle ...
        for (int i = iStartPos -1; (sHaystack.length() >= i + sNeedle.length()) && !iFoundPos; i++) {
            j = 0; // always begin at the first character in haystack (= position 0)
            while (sHaystack[i + j] == sNeedle[j]) // matching the next char, and the next ...
                j == sNeedle.length() -1 ? iFoundPos = i + 1, j++ : j++; // all chars matching? Position begins at 0 instead 1, so "-1" and "+1"
        }
    }
return iFoundPos;
}

string itos(unsigned long long i, unsigned short base) { // Integer zu String
    int len = 0, k = 1;
    unsigned long long j = i, div = 1;
    string s = "";
    if (base == 16) {
        unsigned short rest;
        string str = "", buchstabe = "ABCDEF";
        do { rest = i % 16, i /= 16, rest < 10 ? str += char(rest + 48) : str += buchstabe[rest - 10]; } while (i);
        for (i = str.length(); i > 0; i--) s += str[i-1];
    }
    else {
        for(; j; j /= base) len++;
        if (!len) len = 1;
        for(j = 1; j < len; j++) div *= base;
        for(j = len; j > 0; j--) k = i/div, i = i - (k * div), div /= base, s += char(k + 48);
    }
return s;
}

int ctoi(char c) { // convert char to integer  (Example: c='d'; i=ctoi(c) --> i = 13   ,   s="13b6f"; i=ctoi(s[2])  -->  i = 11)
    if ((c > 57) || c < 48) { // no decimal character
        if ((c > 64) && (c < 71)) return c - 55; // A-F
        else if ((c > 96) && (c < 103)) return c - 87; // a-f
        else return 0; // no hex character, so return 0
    }
return c - 48;
}

string stringToUpper(string s) { // konvertiert alle Kleinbuchstaben zu Grossbuchstaben
    if (s.length()) { // if string not empty...
        for (int i = 0; i < s.length(); i++) { // check every char in string...
            if ((int)s[i] > 96 && (int)s[i] < 123) // if char an lower case...
                s[i] -= 32; // sub 32, to convert to upper case
            // replace german chars...
            else if ((char)s[i] == (char) 'ä') s[i] = 'Ä';
            else if ((char)s[i] == (char) 'ö') s[i] = 'Ö';
            else if ((char)s[i] == (char) 'ü') s[i] = 'Ü';
        }
    }
return s;
}

bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) {
    int i, zahl = 0, start = 0, nullPos = 0;
    string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2);    //Macht alles Groß, außer Sonderzeichen
    string strZahl;

    // Ersetze Soderzeichen mit "normalen" Großbuchstaben
    while (i = strPos("Ä", s1)) s1.replace(i-1,2,"A");
    while (i = strPos("Ö", s1)) s1.replace(i-1,2,"O");
    while (i = strPos("Ü", s1)) s1.replace(i-1,2,"U");
    while (i = strPos("ä", s1)) s1.replace(i-1,2,"A");
    while (i = strPos("ö", s1)) s1.replace(i-1,2,"O");
    while (i = strPos("ü", s1)) s1.replace(i-1,2,"U");
    while (i = strPos("ß", s1)) s1.replace(i-1,2,"SS");
    while (i = strPos("Ä", s2)) s2.replace(i-1,2,"A");
    while (i = strPos("Ö", s2)) s2.replace(i-1,2,"O");
    while (i = strPos("Ü", s2)) s2.replace(i-1,2,"U");
    while (i = strPos("ä", s2)) s2.replace(i-1,2,"A");
    while (i = strPos("ö", s2)) s2.replace(i-1,2,"O");
    while (i = strPos("ü", s2)) s2.replace(i-1,2,"U");
    while (i = strPos("ß", s2)) s2.replace(i-1,2,"SS");

    // 01234 ist größer als 45.
    // Darum:
    // 1. Führende Nullen entfernen
    // 2. Anzahl der Stellen voranstellen
    // 3. Danach kann wieder stelle für Stelle verglichen werden
    // Beispiel: aus 01234 wird "41234" , aus 45 wird "245"
    // ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung

    // Führende Nullen entfernen...

    for (i = 0, start = 1; nullPos = strPos("0",s1,start) ; i++) {
        // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen
        if (nullPos == s1.length()) start++;                    // Die Null ist am Ende, da soll sie bleiben.
        else if ((nullPos == 1) && (s1[1] > 47 && s1[1] < 58))  // Das erste Zeichen ist eine Null, gefolgt von einer Zahl
            s1.erase(0,1), i--;                                 // diese Null löschen
        else if (s1[nullPos-2] < 48 || s1[nullPos-2] > 57)      // Die Null kommt irgendwo ist String vor, davor ist keine Zahl
            s1.erase(nullPos-1,1), i--;                         // diese Null löschen
        else start = nullPos + 1;                               // Die Suche eine Stelle weiter hinten fortsetzen
    }
    for (i = 0, start = 1; (nullPos = strPos("0",s2,start)) && (s2.length() > i); i++) {
        // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen
        if (nullPos == s2.length()) start++;                    // Die Null ist am Ende, da soll sie bleiben.
        else if ((nullPos == 1) && (s2[1] > 47 && s2[1] < 58))  // Das erste Zeichen ist eine Null, gefolgt von einer Zahl
            s2.erase(0,1), i--;                                 // diese Null löschen
        else if (s2[nullPos-2] < 48 || s2[nullPos-2] > 57)      // Die Null kommt irgendwo ist String vor, davor ist keine Zahl
            s2.erase(nullPos-1,1), i--;                         // diese Null löschen
        else start = nullPos + 1;                               // Die Suche eine Stelle weiter hinten fortsetzen
    }

    // Anzahl der Zahlen voranstellen...
    zahl = 0;
    for (i = 0; i <= s1.length(); i++) {
        if (s1[i] > 47 && s1[i] < 58) {                         // Eine Zahl
            if (!zahl) zahl = ctoi(s1[i]);                      // Eine "neue" Zahl...
            else zahl = zahl * 10 + ctoi(s1[i]);                // Die Zahl geht weiter
        }
        else if (zahl) {                                        // Es ist keine Zahl mehr, aber es gab eine Zahl...
            strZahl = itos(zahl);                               // Die Zahl in einen String umwandeln
            strZahl = itos(strZahl.length()) + strZahl;         // Die Anzahl der Stellen voranstellen
            s1 = s1.substr(0,i+1-strZahl.length()) + strZahl + s1.substr(i); // Die Zahl ersetzen
            zahl = 0;
        }
    }
    zahl = 0;
    for (i = 0; i <= s2.length(); i++) {
        if (s2[i] > 47 && s2[i] < 58) {                         // Eine Zahl
            if (!zahl) zahl = ctoi(s2[i]);                      // Eine "neue" Zahl...
            else zahl = zahl * 10 + ctoi(s2[i]);                // Die Zahl geht weiter
        }
        else if (zahl) {                                        // Es ist keine Zahl mehr, aber es gab eine Zahl...
            strZahl = itos(zahl);                               // Die Zahl in einen String umwandeln
            strZahl = itos(strZahl.length()) + strZahl;         // Die Anzahl der Stellen voranstellen
            s2 = s2.substr(0,i+1-strZahl.length()) + strZahl + s2.substr(i); // Die Zahl ersetzen
            zahl = 0;
        }
    }
return (reverse ? s1 > s2 : s1 < s2);
}

void inventur() {
    // gesamte Datei einlesen und in der globalen Variable "ini" speichern (vektor mit 3 Strings)
    string str = "", bezeichnung = "", fach = "", menge = "";
    ifstream fin("Lager.ini");
    while (getline(fin ,str)) {
        if (strPos("[",str) == 1 && strPos("]",str) == str.length()) {              // Kategorie gefunden
            if (bezeichnung.length())                                               // Nächster Eintrag (ansonsten erster Eintrag)
                bezeichnung = "", fach = "", menge = "";                            // Variablen löschen für nächsten Eintrag
            str = str.erase(0, 1);                                                  // Das "[" am Anfang entfernen
            str = str.erase(str.length()-1, 1);                                     // Das "]" am Ende entfernen
            bezeichnung = str;                                                      // "bezeichnung" enthält nun die Kategorie
        }
        if (strPos("Fach_",str) == 1)                                               // Wenn "Fach_x=", dann vorne (inkl. "=") abschneiden
            fach = str.erase(0,strPos("=",str));
        else if (strPos("Menge_",str) == 1)                                         // Wenn "Menge_x=", dann vorne (inkl. "=") abschneiden
            ini.push_back({bezeichnung,fach,str.erase(0,strPos("=",str))});
    }
    fin.close ();
}

void liveSuche() {
    // Die Listbox muss mit jedem Zeichen neu erstellt werden
    listboxLager.auto_draw(false);              // Auto-Draw deaktivieren (geht schneller und vermeidet "flackern")
    listboxLager.clear();                       // die Listbox komplett leeren

    int index = 0;
    string suche = textboxSuchen.caption();     // den Inhalt der TB als Suchstring benutzen

    for (vector<iniInhalt>::const_iterator i=ini.begin(); i!=ini.end(); ++i) {
        if (strPos(stringToUpper(suche),stringToUpper(ini[index].b)) || suche.length() == 0)
            listboxLager.at(0).append({ini[index].b, ini[index].f , ini[index].m});     // Einen Eintrag in die Listbox hinzufügen
        index++;
    }
    listboxLager.sort_col(2),listboxLager.sort_col(1),listboxLager.sort_col(0); // Sortierung Spalte 1, dann Spalte 2, dann Spalte 3
    listboxLager.auto_draw(true);
}

void bearbeiten() {
    form fmBearbeiten(fm,rectangle( -5,  -25, 520,  350),appear::decorate<appear::minimize>());
    fmBearbeiten.caption("Lager bearbeiten");                                               // Fenstertitel
    // ------------------------------------- Icon  -------------------------------------
    wstring app_path(4096, '\0');                                                           // Speichert den Pfad des ausgeführten Programms
    app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size()));             // Passt die Groesse an
    fmBearbeiten.icon(paint::image(app_path));
    fmBearbeiten.bgcolor(color_rgb(bgc));                                                   // Hintergrundfarbe

    // Steuerelemente erstellen
    textbox textboxNeuBezeichnung (fmBearbeiten, rectangle( 10,  33, 300,  22));            // Textbox Bezeichnung

    // Steuerelemente einrichten
    textboxNeuBezeichnung.caption(lastSelect.b);

    // Fenster verschieben durch Kopfzeile
    fmBearbeiten.events().move([fmBearbeiten](const arg_move& arg) {
        fm.move(arg.x,arg.y-25);
    });

    // Fenster verschieben durch Hintergrund
    dragger dg;
    dg.target(fm);
    dg.target(fmBearbeiten);
    dg.trigger(fmBearbeiten);

    fmBearbeiten.modality();
}

To test it you need a INI-File "Lager.ini" :

[Config]
Anzahl=41
[5200-0101]
Fach_1=F019-Kiste
Menge_1=viele
Fach_2=Görlich
Menge_2=
Fach_3=Mäusekloo
Menge_3=ca. 20
Fach_4=F4
Menge_4=M4
Fach_5=F5
Menge_5=M5
Fach_6=F6
Menge_6=M6
Fach_7=F7
Menge_7=M7
Fach_8=F8
Menge_8=M8
Fach_9=F9
Menge_9=M9
Fach_10=F10
Menge_10=M10
Fach_11=F11
Menge_11=M11
Fach_12=F12
Menge_12=M12
[aaaaa]
Fach_1=aaa
Menge_1=a
[5241-0009]
Fach_1=Stäubli
Fach_2=F019-Kiste
Menge_2=3
[T00345]
Fach_1=12/5/2
Menge_1=1
Kommentar=Adapter T00789 in F019-Kiste
[CAN Hilfsrechner]
Fach_1=11/1/1
Menge_1=4
[UNC-Bolzen]
Fach_1=Stäubli
Menge_1=ca.10
Kommentar=Nur die mit Kerbe verwenden !!!
[bbb]
Fach_1=bbb
Menge_1=b
[ccc]
Fach_1=ccc
Menge_1=c
[ddd]
Fach_1=ddd
Menge_1=d
[eee]
Fach_1=eee
Menge_1=e
[fff]
Fach_1=fff
Menge_1=f
[ggg]
Fach_1=ggg
Menge_1=g
[hhh]
Fach_1=hhh
Menge_1=h
[iii]
Fach_1=iii
Menge_1=i
[jjj]
Fach_1=jjj
Menge_1=j
[KKK]
Fach_1=KKK
Menge_1=K
[lll]
Fach_1=lll
Menge_1=l
[mmm]
Fach_1=mmm
Menge_1=m
[nnn]
Fach_1=nnn
Menge_1=n
[ooo]
Fach_1=ooo
Menge_1=o
[äöüß]
Fach_1=äöüß
Menge_1=äöüß
[Ähhm]
Fach_1=Ähhm
Menge_1=Ähhm
[ßaaa]
Fach_1=ßaaa
Menge_1=ßaaa
[1abc1234de]
Fach_1=blubb
Menge_1=blubb
[1abc123de]
Fach_1=blubb
Menge_1=blubb
[1abc01234de]
Fach_1=blubb
Menge_1=blubb
[1abc123dy]
Fach_1=blubb
Menge_1=blubb
[1abc123de]
Fach_1=blubb
Menge_1=blubb
[abc123dy]
Fach_1=blubb
Menge_1=blubb
[abc1230dy]
Fach_1=blubb
Menge_1=blubb
[F10]
Fach_1=äöhm
Menge_1=x
[F4]
Fach_1=aöhm
Menge_1=y

Btw, when I double click in the listbox on a selected row, so "lastselect.b" is empty. I found solution (lastSelectBefore), but this solution is not the best way. Do you have a better Idea?

I have replaced all [fm] by [&WidgetName], it works fine. But I cant put this in the main: ```` form fm(API::make_center(520,350),appear::decorate<appear::minimize>()); // Steuerelemente erstellen label labelSuchen (fm, rectangle( 10, 10, 200, 22)); // Label Suchen textbox textboxSuchen (fm, rectangle( 10, 33, 300, 22)); // Textbox Suchen listbox listboxLager (fm, rectangle( 10, 70, 500, 180)); // Listbox Lager button buttonNeu (fm, rectangle( 10, 300, 120, 30)); // Button Bearbeiten button buttonBeenden (fm, rectangle(150, 300, 120, 30)); // Button Beenden label debug (fm, rectangle(300, 300, 210, 30)); ```` ...because I need to change from functions. My program is not completed at this moment, but I will show you, so you can understand much easier what i am working for. Sorry for my bad english, and sorry for german comments. Here is the program: ```` #include <fstream> // fuer Dateibehandlungen // #include <stdlib.h> // fuer Zufall #include <string.h> // fuer Strings // #include <time.h> // fuer Zufall #include <vector> // für Vektoren (dynamische Arrays) #include <windows.h> // fuer Windows-Funktionen #include<nana/gui/dragger.hpp> // Drag & Drop #include <nana/gui/wvl.hpp> // Nana Klasswendefinition #include <nana/gui/msgbox.hpp> // fuer Message-Boxen // #include <nana/gui/timer.hpp> // fuer Timer #include <nana/gui/tooltip.hpp> // fuer Tooltips #include <nana/gui/widgets/button.hpp> // fuer Buttons // #include <nana/gui/widgets/checkbox.hpp> // fuer Check-Boxen // #include <nana/gui/widgets/group.hpp> // fuer Gruppen #include <nana/gui/widgets/label.hpp> // fuer Label #include <nana/gui/widgets/listbox.hpp> // fuer Listbox // #include <nana/gui/widgets/slider.hpp> // fuer Slider #include <nana/gui/widgets/textbox.hpp> // fuer Text-Boxen // Namespaces using namespace std; using namespace nana; // Globale Variablen //{ int bgc = 0xF4F4FB; // Hintergrundfarbe struct iniInhalt { string b, f, m; }; // Eine Struktur für den Lagerinhalt vector<iniInhalt> ini; // Eine Variable des Types iniInhalt iniInhalt lastSelect = {"","",""}; // letzte Auswahl in der Listbox iniInhalt lastSelectBefore = {"","",""}; // vorletzte Auswahl in der Listbox (fuer Doppelklick) //} // Deklarationen //{ int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0); // Vereinfachte Erstellung einer MessageBox int strPos(string sNeedle, string sHaystack, int iStartPos = 1); // Ermittelt die Position in einem String string itos(unsigned long long i, unsigned short base = 10); // Macht aus Zahlen Strings int ctoi(char c); // Wandelt String-Zahlen in Integer-Zahlen string stringToUpper(string s); // Wandelt alles in Großbuchstaben bool sort_compare_insensitive(const string& s1, any*, const string& s2, any*, bool reverse); // Sortiert alphabetisch (ohne Groß-Kein-Unterscheidung) void inventur(); // Gibt den gesamten Lagerbestand zurück. void liveSuche(); // Prüft ob der Suchtext in der Listbox vorhanden ist void bearbeiten(); // zum bearbeiten/hinzufügen eines Eintrages //} // ************************************* GUI erstellen ************************************** // --------------------- Fenster und Steuerelemente erstellen (global) ---------------------- //{ // Fenster erstellen form fm(API::make_center(520,350),appear::decorate<appear::minimize>()); // Steuerelemente erstellen label labelSuchen (fm, rectangle( 10, 10, 200, 22)); // Label Suchen textbox textboxSuchen (fm, rectangle( 10, 33, 300, 22)); // Textbox Suchen listbox listboxLager (fm, rectangle( 10, 70, 500, 180)); // Listbox Lager button buttonNeu (fm, rectangle( 10, 300, 120, 30)); // Button Bearbeiten button buttonBeenden (fm, rectangle(150, 300, 120, 30)); // Button Beenden label debug (fm, rectangle(300, 300, 210, 30)); //} int main() { // Das Fenster verschiebbar machen, indem man einfach ins Fenster klickt und die Maus zieht. dragger dgMain; dgMain.target(fm); dgMain.trigger(fm); // ------------------------------------- Icon ------------------------------------- wstring app_path(4096, '\0'); // Speichert den Pfad des ausgeführten Programms app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size())); // Passt die Groesse an fm.icon(paint::image(app_path)); // Verwendet das Icon der EXE (dieses ist per Recource festgelegt) // ----------------------------- Variablen deklarieren ----------------------------- string str; // für temporaere Strings string lagerIni; // Lädt den gesamten Lagerbestand in die Variable // ------------------------- Steuerelemente "einrichten" --------------------------- // Fenster fm.caption("Store Manager v1.0"); // Fenstertitel fm.bgcolor(color_rgb(bgc)); // Hintergrundfarbe // Label Suchen labelSuchen.bgcolor(color_rgb(bgc)); // Hintergrundfarbe labelSuchen.format(true); // Ermoeglicht HTML-Formatierung labelSuchen.caption({ // Text "Comic Sans MS" "<size=12, bold=false, font=\"Comic Sans MS\">Suche nach:</>"}); labelSuchen.tooltip("Wonach gesucht werden soll..."); // Tooltip // Textbox Suchen textboxSuchen.multi_lines(false); // Nur eine Zeile erlaubt textboxSuchen.typeface(paint::font{"Comic Sans MS", 10}); // Schrift und Schriftgroesse textboxSuchen.focus(); // Setzt den Focus textboxSuchen.events().text_changed(liveSuche); // Ruft die Live-Suche auf textboxSuchen.events().key_char([&textboxSuchen](const arg_keyboard& arg) { // Event Taste if (arg.key == keyboard::enter) mbox("Fehlt noch!"); // Wenn Enter ... // hier sollte nun in das nächste Suchfeld gesprungen werden }); // Listbox Lager listboxLager.enable_single(true,1); // Erlaubt nur eine Auswahl (keine Mehrfachauswahl) listboxLager.typeface(paint::font{"Comic Sans MS", 10}); // Schrift und Schriftgroesse für die Listbox listboxLager.append_header("Bezeichnung", 180); // Spalte "Bezeichnung" listboxLager.append_header("Lagerort", 230); // Spalte "Lagerort" listboxLager.append_header("Menge", 65); // Spalte "Menge" listboxLager.column_at(0).typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse für die Überschrift der Spalte 0 listboxLager.column_at(1).typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse für die Überschrift der Spalte 1 listboxLager.column_at(2).typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse für die Überschrift der Spalte 2 listboxLager.sortable(true); listboxLager.auto_draw(false); listboxLager.set_sort_compare(0, sort_compare_insensitive); // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung listboxLager.set_sort_compare(1, sort_compare_insensitive); // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung listboxLager.set_sort_compare(2, sort_compare_insensitive); // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung inventur(); // Liest die Daten aus der INI-Datei liveSuche(); // Filtert die Listbox nach dem Suchstring listboxLager.auto_draw(true); listboxLager.events().selected([&listboxLager](const arg_listbox& arg) { if(arg.item.selected()) { lastSelect = {arg.item.text(0),arg.item.text(1),arg.item.text(2)}; if (lastSelect.b != "") lastSelectBefore = lastSelect; // beim Doppelklick wird markiert/demarkiert } else lastSelect = {}; }); listboxLager.events().dbl_click([&listboxLager](const arg_mouse &arg) { // beim Doppelklick merken wo die Maus steht if(!listboxLager.cast(arg.pos).empty()) { // Wenn die auf einen Eintrag steht... if (lastSelect.b == "") lastSelect = lastSelectBefore; bearbeiten(); } }); listboxLager.events().key_char([&listboxLager](const arg_keyboard& arg) { // Event Taste Enter if ((arg.key == keyboard::enter) && (lastSelect.b != "")) bearbeiten(); // Wenn Enter bei selektierter Listbox --> ... }); // Button Neu buttonNeu.typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse buttonNeu.caption("Neuer Eintrag"); // Beschriftung des Button //buttonNeu.caption((wstring)charset("Neuer Eintrag")); // Beschriftung des Button (in UTF-8) buttonNeu.enable_focus_color(false); // Die "Fokus-Farbe" deaktivieren buttonNeu.events().click([&buttonNeu]() { bearbeiten(); }); // Event: Click LM buttonNeu.events().key_char([&buttonNeu](const arg_keyboard& arg) { // Event Taste Enter if (arg.key == keyboard::enter) bearbeiten(); // Wenn Enter bei focusierten Button --> ... }); // Button Beenden buttonBeenden.typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse buttonBeenden.caption("Beenden"); // Beschriftung des Button buttonBeenden.enable_focus_color(false); // Die "Fokus-Farbe" deaktivieren buttonBeenden.events().click(API::exit_all); // Event: Click LM buttonBeenden.events().key_char([&buttonBeenden](const arg_keyboard& arg) { // Event Taste Enter if (arg.key == keyboard::enter) API::exit_all(); // Wenn Enter bei focusierten Button --> Programm schließen }); // GUI anzeigen fm.show(); // GUI sichtbar machen exec(); // Endlosschleife bis die GUI zerstoert wird (warten auf Ereignisse) return 0; } int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) { // Vereinfachte Erstellung einer MessageBox // int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) { // MessageBox mit Nana // mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner]) // ---- Bedeutung der Werte ---- // Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen // Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage // Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein unsigned short auswahl; msgbox::button_t buttons; switch(art) { // Buttonauswahl case 1: buttons = msgbox::yes_no; break; case 2: buttons = msgbox::yes_no_cancel; break; default: buttons = msgbox::ok; break; } msgbox m(fenster, titel, buttons); // Die Messagebox erstellen m << inhalt; // Den Inhalt (Text) einfuegen switch(symbol) { // Ein Icon hinzufuegen case 1: m.icon(m.icon_information); break; case 2: m.icon(m.icon_warning); break; case 3: m.icon(m.icon_error); break; case 4: m.icon(m.icon_question); break; } auto response = m(); // Auf eine Auswahl warten switch(response) { // Die Auswahl als Integer zurueckliefern case m.pick_ok: auswahl = 1; break; case m.pick_yes: auswahl = 2; break; case m.pick_no: auswahl = 3; break; default: auswahl = 0; break; } return auswahl; } int strPos(string sNeedle, string sHaystack, int iStartPos) { // needs #include <string> // search needle in haystack unsigned short iFoundPos = 0, j; // if haystack >= needle... if (sHaystack.length() >= sNeedle.length()) { // while haystack is big enough to contain the needle ... for (int i = iStartPos -1; (sHaystack.length() >= i + sNeedle.length()) && !iFoundPos; i++) { j = 0; // always begin at the first character in haystack (= position 0) while (sHaystack[i + j] == sNeedle[j]) // matching the next char, and the next ... j == sNeedle.length() -1 ? iFoundPos = i + 1, j++ : j++; // all chars matching? Position begins at 0 instead 1, so "-1" and "+1" } } return iFoundPos; } string itos(unsigned long long i, unsigned short base) { // Integer zu String int len = 0, k = 1; unsigned long long j = i, div = 1; string s = ""; if (base == 16) { unsigned short rest; string str = "", buchstabe = "ABCDEF"; do { rest = i % 16, i /= 16, rest < 10 ? str += char(rest + 48) : str += buchstabe[rest - 10]; } while (i); for (i = str.length(); i > 0; i--) s += str[i-1]; } else { for(; j; j /= base) len++; if (!len) len = 1; for(j = 1; j < len; j++) div *= base; for(j = len; j > 0; j--) k = i/div, i = i - (k * div), div /= base, s += char(k + 48); } return s; } int ctoi(char c) { // convert char to integer (Example: c='d'; i=ctoi(c) --> i = 13 , s="13b6f"; i=ctoi(s[2]) --> i = 11) if ((c > 57) || c < 48) { // no decimal character if ((c > 64) && (c < 71)) return c - 55; // A-F else if ((c > 96) && (c < 103)) return c - 87; // a-f else return 0; // no hex character, so return 0 } return c - 48; } string stringToUpper(string s) { // konvertiert alle Kleinbuchstaben zu Grossbuchstaben if (s.length()) { // if string not empty... for (int i = 0; i < s.length(); i++) { // check every char in string... if ((int)s[i] > 96 && (int)s[i] < 123) // if char an lower case... s[i] -= 32; // sub 32, to convert to upper case // replace german chars... else if ((char)s[i] == (char) 'ä') s[i] = 'Ä'; else if ((char)s[i] == (char) 'ö') s[i] = 'Ö'; else if ((char)s[i] == (char) 'ü') s[i] = 'Ü'; } } return s; } bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) { int i, zahl = 0, start = 0, nullPos = 0; string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2); //Macht alles Groß, außer Sonderzeichen string strZahl; // Ersetze Soderzeichen mit "normalen" Großbuchstaben while (i = strPos("Ä", s1)) s1.replace(i-1,2,"A"); while (i = strPos("Ö", s1)) s1.replace(i-1,2,"O"); while (i = strPos("Ü", s1)) s1.replace(i-1,2,"U"); while (i = strPos("ä", s1)) s1.replace(i-1,2,"A"); while (i = strPos("ö", s1)) s1.replace(i-1,2,"O"); while (i = strPos("ü", s1)) s1.replace(i-1,2,"U"); while (i = strPos("ß", s1)) s1.replace(i-1,2,"SS"); while (i = strPos("Ä", s2)) s2.replace(i-1,2,"A"); while (i = strPos("Ö", s2)) s2.replace(i-1,2,"O"); while (i = strPos("Ü", s2)) s2.replace(i-1,2,"U"); while (i = strPos("ä", s2)) s2.replace(i-1,2,"A"); while (i = strPos("ö", s2)) s2.replace(i-1,2,"O"); while (i = strPos("ü", s2)) s2.replace(i-1,2,"U"); while (i = strPos("ß", s2)) s2.replace(i-1,2,"SS"); // 01234 ist größer als 45. // Darum: // 1. Führende Nullen entfernen // 2. Anzahl der Stellen voranstellen // 3. Danach kann wieder stelle für Stelle verglichen werden // Beispiel: aus 01234 wird "41234" , aus 45 wird "245" // ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung // Führende Nullen entfernen... for (i = 0, start = 1; nullPos = strPos("0",s1,start) ; i++) { // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen if (nullPos == s1.length()) start++; // Die Null ist am Ende, da soll sie bleiben. else if ((nullPos == 1) && (s1[1] > 47 && s1[1] < 58)) // Das erste Zeichen ist eine Null, gefolgt von einer Zahl s1.erase(0,1), i--; // diese Null löschen else if (s1[nullPos-2] < 48 || s1[nullPos-2] > 57) // Die Null kommt irgendwo ist String vor, davor ist keine Zahl s1.erase(nullPos-1,1), i--; // diese Null löschen else start = nullPos + 1; // Die Suche eine Stelle weiter hinten fortsetzen } for (i = 0, start = 1; (nullPos = strPos("0",s2,start)) && (s2.length() > i); i++) { // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen if (nullPos == s2.length()) start++; // Die Null ist am Ende, da soll sie bleiben. else if ((nullPos == 1) && (s2[1] > 47 && s2[1] < 58)) // Das erste Zeichen ist eine Null, gefolgt von einer Zahl s2.erase(0,1), i--; // diese Null löschen else if (s2[nullPos-2] < 48 || s2[nullPos-2] > 57) // Die Null kommt irgendwo ist String vor, davor ist keine Zahl s2.erase(nullPos-1,1), i--; // diese Null löschen else start = nullPos + 1; // Die Suche eine Stelle weiter hinten fortsetzen } // Anzahl der Zahlen voranstellen... zahl = 0; for (i = 0; i <= s1.length(); i++) { if (s1[i] > 47 && s1[i] < 58) { // Eine Zahl if (!zahl) zahl = ctoi(s1[i]); // Eine "neue" Zahl... else zahl = zahl * 10 + ctoi(s1[i]); // Die Zahl geht weiter } else if (zahl) { // Es ist keine Zahl mehr, aber es gab eine Zahl... strZahl = itos(zahl); // Die Zahl in einen String umwandeln strZahl = itos(strZahl.length()) + strZahl; // Die Anzahl der Stellen voranstellen s1 = s1.substr(0,i+1-strZahl.length()) + strZahl + s1.substr(i); // Die Zahl ersetzen zahl = 0; } } zahl = 0; for (i = 0; i <= s2.length(); i++) { if (s2[i] > 47 && s2[i] < 58) { // Eine Zahl if (!zahl) zahl = ctoi(s2[i]); // Eine "neue" Zahl... else zahl = zahl * 10 + ctoi(s2[i]); // Die Zahl geht weiter } else if (zahl) { // Es ist keine Zahl mehr, aber es gab eine Zahl... strZahl = itos(zahl); // Die Zahl in einen String umwandeln strZahl = itos(strZahl.length()) + strZahl; // Die Anzahl der Stellen voranstellen s2 = s2.substr(0,i+1-strZahl.length()) + strZahl + s2.substr(i); // Die Zahl ersetzen zahl = 0; } } return (reverse ? s1 > s2 : s1 < s2); } void inventur() { // gesamte Datei einlesen und in der globalen Variable "ini" speichern (vektor mit 3 Strings) string str = "", bezeichnung = "", fach = "", menge = ""; ifstream fin("Lager.ini"); while (getline(fin ,str)) { if (strPos("[",str) == 1 && strPos("]",str) == str.length()) { // Kategorie gefunden if (bezeichnung.length()) // Nächster Eintrag (ansonsten erster Eintrag) bezeichnung = "", fach = "", menge = ""; // Variablen löschen für nächsten Eintrag str = str.erase(0, 1); // Das "[" am Anfang entfernen str = str.erase(str.length()-1, 1); // Das "]" am Ende entfernen bezeichnung = str; // "bezeichnung" enthält nun die Kategorie } if (strPos("Fach_",str) == 1) // Wenn "Fach_x=", dann vorne (inkl. "=") abschneiden fach = str.erase(0,strPos("=",str)); else if (strPos("Menge_",str) == 1) // Wenn "Menge_x=", dann vorne (inkl. "=") abschneiden ini.push_back({bezeichnung,fach,str.erase(0,strPos("=",str))}); } fin.close (); } void liveSuche() { // Die Listbox muss mit jedem Zeichen neu erstellt werden listboxLager.auto_draw(false); // Auto-Draw deaktivieren (geht schneller und vermeidet "flackern") listboxLager.clear(); // die Listbox komplett leeren int index = 0; string suche = textboxSuchen.caption(); // den Inhalt der TB als Suchstring benutzen for (vector<iniInhalt>::const_iterator i=ini.begin(); i!=ini.end(); ++i) { if (strPos(stringToUpper(suche),stringToUpper(ini[index].b)) || suche.length() == 0) listboxLager.at(0).append({ini[index].b, ini[index].f , ini[index].m}); // Einen Eintrag in die Listbox hinzufügen index++; } listboxLager.sort_col(2),listboxLager.sort_col(1),listboxLager.sort_col(0); // Sortierung Spalte 1, dann Spalte 2, dann Spalte 3 listboxLager.auto_draw(true); } void bearbeiten() { form fmBearbeiten(fm,rectangle( -5, -25, 520, 350),appear::decorate<appear::minimize>()); fmBearbeiten.caption("Lager bearbeiten"); // Fenstertitel // ------------------------------------- Icon ------------------------------------- wstring app_path(4096, '\0'); // Speichert den Pfad des ausgeführten Programms app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size())); // Passt die Groesse an fmBearbeiten.icon(paint::image(app_path)); fmBearbeiten.bgcolor(color_rgb(bgc)); // Hintergrundfarbe // Steuerelemente erstellen textbox textboxNeuBezeichnung (fmBearbeiten, rectangle( 10, 33, 300, 22)); // Textbox Bezeichnung // Steuerelemente einrichten textboxNeuBezeichnung.caption(lastSelect.b); // Fenster verschieben durch Kopfzeile fmBearbeiten.events().move([fmBearbeiten](const arg_move& arg) { fm.move(arg.x,arg.y-25); }); // Fenster verschieben durch Hintergrund dragger dg; dg.target(fm); dg.target(fmBearbeiten); dg.trigger(fmBearbeiten); fmBearbeiten.modality(); } ```` To test it you need a INI-File "Lager.ini" : ```` [Config] Anzahl=41 [5200-0101] Fach_1=F019-Kiste Menge_1=viele Fach_2=Görlich Menge_2= Fach_3=Mäusekloo Menge_3=ca. 20 Fach_4=F4 Menge_4=M4 Fach_5=F5 Menge_5=M5 Fach_6=F6 Menge_6=M6 Fach_7=F7 Menge_7=M7 Fach_8=F8 Menge_8=M8 Fach_9=F9 Menge_9=M9 Fach_10=F10 Menge_10=M10 Fach_11=F11 Menge_11=M11 Fach_12=F12 Menge_12=M12 [aaaaa] Fach_1=aaa Menge_1=a [5241-0009] Fach_1=Stäubli Fach_2=F019-Kiste Menge_2=3 [T00345] Fach_1=12/5/2 Menge_1=1 Kommentar=Adapter T00789 in F019-Kiste [CAN Hilfsrechner] Fach_1=11/1/1 Menge_1=4 [UNC-Bolzen] Fach_1=Stäubli Menge_1=ca.10 Kommentar=Nur die mit Kerbe verwenden !!! [bbb] Fach_1=bbb Menge_1=b [ccc] Fach_1=ccc Menge_1=c [ddd] Fach_1=ddd Menge_1=d [eee] Fach_1=eee Menge_1=e [fff] Fach_1=fff Menge_1=f [ggg] Fach_1=ggg Menge_1=g [hhh] Fach_1=hhh Menge_1=h [iii] Fach_1=iii Menge_1=i [jjj] Fach_1=jjj Menge_1=j [KKK] Fach_1=KKK Menge_1=K [lll] Fach_1=lll Menge_1=l [mmm] Fach_1=mmm Menge_1=m [nnn] Fach_1=nnn Menge_1=n [ooo] Fach_1=ooo Menge_1=o [äöüß] Fach_1=äöüß Menge_1=äöüß [Ähhm] Fach_1=Ähhm Menge_1=Ähhm [ßaaa] Fach_1=ßaaa Menge_1=ßaaa [1abc1234de] Fach_1=blubb Menge_1=blubb [1abc123de] Fach_1=blubb Menge_1=blubb [1abc01234de] Fach_1=blubb Menge_1=blubb [1abc123dy] Fach_1=blubb Menge_1=blubb [1abc123de] Fach_1=blubb Menge_1=blubb [abc123dy] Fach_1=blubb Menge_1=blubb [abc1230dy] Fach_1=blubb Menge_1=blubb [F10] Fach_1=äöhm Menge_1=x [F4] Fach_1=aöhm Menge_1=y ```` Btw, when I double click in the listbox on a selected row, so "lastselect.b" is empty. I found solution (lastSelectBefore), but this solution is not the best way. Do you have a better Idea?

You can just declare some global pointers, and assign to them the object addresses in the main. Then, use the pointers in your functions:

#include <fstream>                              // fuer Dateibehandlungen
// #include <stdlib.h>                             // fuer Zufall
#include <string.h>                             // fuer Strings
// #include <time.h>                               // fuer Zufall
#include <vector>                               // für Vektoren (dynamische Arrays)
#include <windows.h>                            // fuer Windows-Funktionen
#include<nana/gui/dragger.hpp>                  // Drag & Drop
#include <nana/gui/wvl.hpp>                     // Nana Klasswendefinition
#include <nana/gui/msgbox.hpp>                  // fuer Message-Boxen
// #include <nana/gui/timer.hpp>                   // fuer Timer
#include <nana/gui/tooltip.hpp>                 // fuer Tooltips
#include <nana/gui/widgets/button.hpp>          // fuer Buttons
// #include <nana/gui/widgets/checkbox.hpp>        // fuer Check-Boxen
// #include <nana/gui/widgets/group.hpp>           // fuer Gruppen
#include <nana/gui/widgets/label.hpp>           // fuer Label
#include <nana/gui/widgets/listbox.hpp>         // fuer Listbox
// #include <nana/gui/widgets/slider.hpp>          // fuer Slider
#include <nana/gui/widgets/textbox.hpp>         // fuer Text-Boxen



// Namespaces
using namespace std;
using namespace nana;

// Globale Variablen
//{
int bgc = 0xF4F4FB;                                 // Hintergrundfarbe
struct iniInhalt { string b, f, m; };               // Eine Struktur für den Lagerinhalt
vector<iniInhalt> ini;                              // Eine Variable des Types iniInhalt
iniInhalt lastSelect = {"","",""};                  // letzte Auswahl in der Listbox
iniInhalt lastSelectBefore = {"","",""};            // vorletzte Auswahl in der Listbox (fuer Doppelklick)
                                                    //}

                                                    // Deklarationen
                                                    //{
int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0); // Vereinfachte Erstellung einer MessageBox
int strPos(string sNeedle, string sHaystack, int iStartPos = 1);                                // Ermittelt die Position in einem String
string itos(unsigned long long i, unsigned short base = 10);                                    // Macht aus Zahlen Strings
int ctoi(char c);                                                                               // Wandelt String-Zahlen in Integer-Zahlen
string stringToUpper(string s);                                                                 // Wandelt alles in Großbuchstaben
bool sort_compare_insensitive(const string& s1, any*, const string& s2, any*, bool reverse);    // Sortiert alphabetisch (ohne Groß-Kein-Unterscheidung)
void inventur();                                                                                // Gibt den gesamten Lagerbestand zurück.
void liveSuche();                                                                               // Prüft ob der Suchtext in der Listbox vorhanden ist
void bearbeiten();                                                                              // zum bearbeiten/hinzufügen eines Eintrages
                                                                                                //}

                                                                                                // ************************************* GUI erstellen **************************************
                                                                                                // --------------------- Fenster und Steuerelemente erstellen (global) ----------------------
                                                                                                //{
                                                                                                // Fenster erstellen

listbox *p_listboxLager{nullptr};
textbox *p_textboxSuchen{nullptr};
form *p_fm{nullptr};

//}

int main() {

    form fm(API::make_center(520, 350), appear::decorate<appear::minimize>());
    p_fm = &fm;

    // Steuerelemente erstellen
    label labelSuchen(fm, rectangle(10, 10, 200, 22));            // Label Suchen
    textbox textboxSuchen(fm, rectangle(10, 33, 300, 22));            // Textbox Suchen
    p_textboxSuchen = &textboxSuchen;
    listbox listboxLager(fm, rectangle(10, 70, 500, 180));            // Listbox Lager
    p_listboxLager = &listboxLager;
    button buttonNeu(fm, rectangle(10, 300, 120, 30));            // Button Bearbeiten
    button buttonBeenden(fm, rectangle(150, 300, 120, 30));            // Button Beenden

    label debug(fm, rectangle(300, 300, 210, 30));

    // Das Fenster verschiebbar machen, indem man einfach ins Fenster klickt und die Maus zieht.
    dragger dgMain;
    dgMain.target(fm);
    dgMain.trigger(fm);

    // ------------------------------------- Icon  -------------------------------------
    wstring app_path(4096, '\0');                                                   // Speichert den Pfad des ausgeführten Programms
    app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size()));     // Passt die Groesse an
    fm.icon(paint::image(app_path));                                                // Verwendet das Icon der EXE (dieses ist per Recource festgelegt)

                                                                                    // ----------------------------- Variablen deklarieren -----------------------------
    string str;                                                                     // für temporaere Strings
    string lagerIni;                                                                // Lädt den gesamten Lagerbestand in die Variable

                                                                                    // ------------------------- Steuerelemente "einrichten" ---------------------------

                                                                                    // Fenster
    fm.caption("Store Manager v1.0");                                           // Fenstertitel
    fm.bgcolor(color_rgb(bgc));                                                 // Hintergrundfarbe

                                                                                // Label Suchen
    labelSuchen.bgcolor(color_rgb(bgc));                                        // Hintergrundfarbe
    labelSuchen.format(true);                                                   // Ermoeglicht HTML-Formatierung
    labelSuchen.caption({                                                       // Text "Comic Sans MS"
        "<size=12, bold=false, font=\"Comic Sans MS\">Suche nach:</>"});
    labelSuchen.tooltip("Wonach gesucht werden soll...");                       // Tooltip

                                                                                // Textbox Suchen
    textboxSuchen.multi_lines(false);                                           // Nur eine Zeile erlaubt
    textboxSuchen.typeface(paint::font{"Comic Sans MS", 10});                   // Schrift und Schriftgroesse
    textboxSuchen.focus();                                                      // Setzt den Focus
    textboxSuchen.events().text_changed(liveSuche);                             // Ruft die Live-Suche auf
    textboxSuchen.events().key_char([&textboxSuchen](const arg_keyboard& arg) { // Event Taste
        if(arg.key == keyboard::enter) mbox("Fehlt noch!");                    // Wenn Enter ...
                                                                               // hier sollte nun in das nächste Suchfeld gesprungen werden
    });

    //  Listbox Lager
    listboxLager.enable_single(true, 1);                                         // Erlaubt nur eine Auswahl (keine Mehrfachauswahl)
    listboxLager.typeface(paint::font{"Comic Sans MS", 10});                    // Schrift und Schriftgroesse für die Listbox
    listboxLager.append_header("Bezeichnung", 180);                             // Spalte "Bezeichnung"
    listboxLager.append_header("Lagerort", 230);                                // Spalte "Lagerort"
    listboxLager.append_header("Menge", 65);                                    // Spalte "Menge"
    listboxLager.column_at(0).typeface(paint::font{"Comic Sans MS", 12});       // Schrift und Schriftgroesse für die Überschrift der Spalte 0
    listboxLager.column_at(1).typeface(paint::font{"Comic Sans MS", 12});       // Schrift und Schriftgroesse für die Überschrift der Spalte 1
    listboxLager.column_at(2).typeface(paint::font{"Comic Sans MS", 12});       // Schrift und Schriftgroesse für die Überschrift der Spalte 2
    listboxLager.sortable(true);
    listboxLager.auto_draw(false);
    listboxLager.set_sort_compare(0, sort_compare_insensitive);                 // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung
    listboxLager.set_sort_compare(1, sort_compare_insensitive);                 // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung
    listboxLager.set_sort_compare(2, sort_compare_insensitive);                 // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung
    inventur();                                                                 // Liest die Daten aus der INI-Datei
    liveSuche();                                                                // Filtert die Listbox nach dem Suchstring
    listboxLager.auto_draw(true);
    listboxLager.events().selected([&listboxLager](const arg_listbox& arg) {
        if(arg.item.selected()) {
            lastSelect = {arg.item.text(0),arg.item.text(1),arg.item.text(2)};
            if(lastSelect.b != "") lastSelectBefore = lastSelect;              // beim Doppelklick wird markiert/demarkiert
        }
        else lastSelect = {};
    });
    listboxLager.events().dbl_click([&listboxLager](const arg_mouse &arg) {     // beim Doppelklick merken wo die Maus steht
        if(!listboxLager.cast(arg.pos).empty()) {                               // Wenn die auf einen Eintrag steht...
            if(lastSelect.b == "") lastSelect = lastSelectBefore;
            bearbeiten();
        }
    });
    listboxLager.events().key_char([&listboxLager](const arg_keyboard& arg) {   // Event Taste Enter
        if((arg.key == keyboard::enter) && (lastSelect.b != "")) bearbeiten(); // Wenn Enter bei selektierter Listbox --> ...
    });

    // Button Neu
    buttonNeu.typeface(paint::font{"Comic Sans MS", 12});                       // Schrift und Schriftgroesse
    buttonNeu.caption("Neuer Eintrag");                                         // Beschriftung des Button
                                                                                //buttonNeu.caption((wstring)charset("Neuer Eintrag"));                       // Beschriftung des Button (in UTF-8)
    buttonNeu.enable_focus_color(false);                                        // Die "Fokus-Farbe" deaktivieren
    buttonNeu.events().click([&buttonNeu]() { bearbeiten(); });                 // Event: Click LM
    buttonNeu.events().key_char([&buttonNeu](const arg_keyboard& arg) {         // Event Taste Enter
        if(arg.key == keyboard::enter) bearbeiten();                           // Wenn Enter bei focusierten Button --> ...
    });

    // Button Beenden
    buttonBeenden.typeface(paint::font{"Comic Sans MS", 12});                   // Schrift und Schriftgroesse
    buttonBeenden.caption("Beenden");                                           // Beschriftung des Button
    buttonBeenden.enable_focus_color(false);                                    // Die "Fokus-Farbe" deaktivieren
    buttonBeenden.events().click(API::exit_all);                                // Event: Click LM
    buttonBeenden.events().key_char([&buttonBeenden](const arg_keyboard& arg) { // Event Taste Enter
        if(arg.key == keyboard::enter) API::exit_all();                        // Wenn Enter bei focusierten Button --> Programm schließen
    });

    // GUI anzeigen
    fm.show();                                                                  // GUI sichtbar machen
    exec();                                                                     // Endlosschleife bis die GUI zerstoert wird (warten auf Ereignisse)
    return 0;
}

int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) {    // Vereinfachte Erstellung einer MessageBox
                                                                                                      // int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) {

                                                                                                      // MessageBox mit Nana
                                                                                                      // mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner])
                                                                                                      // ---- Bedeutung der Werte ----
                                                                                                      // Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen
                                                                                                      // Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage
                                                                                                      // Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein
    unsigned short auswahl;
    msgbox::button_t buttons;
    switch(art) { // Buttonauswahl
    case 1: buttons = msgbox::yes_no;           break;
    case 2: buttons = msgbox::yes_no_cancel;    break;
    default: buttons = msgbox::ok;              break;
    }
    msgbox m(fenster, titel, buttons); // Die Messagebox erstellen
    m << inhalt; // Den Inhalt (Text) einfuegen
    switch(symbol) { // Ein Icon hinzufuegen
    case 1: m.icon(m.icon_information);   break;
    case 2: m.icon(m.icon_warning);       break;
    case 3: m.icon(m.icon_error);         break;
    case 4: m.icon(m.icon_question);      break;
    }
    auto response = m(); // Auf eine Auswahl warten
    switch(response) { // Die Auswahl als Integer zurueckliefern
    case m.pick_ok: auswahl = 1;   break;
    case m.pick_yes: auswahl = 2;  break;
    case m.pick_no: auswahl = 3;   break;
    default: auswahl = 0;          break;
    }
    return auswahl;
}

int strPos(string sNeedle, string sHaystack, int iStartPos) { // needs #include <string>
                                                              // search needle in haystack
    unsigned short iFoundPos = 0, j;
    // if haystack >= needle...
    if(sHaystack.length() >= sNeedle.length()) {
        // while haystack is big enough to contain the needle ...
        for(int i = iStartPos -1; (sHaystack.length() >= i + sNeedle.length()) && !iFoundPos; i++) {
            j = 0; // always begin at the first character in haystack (= position 0)
            while(sHaystack[i + j] == sNeedle[j]) // matching the next char, and the next ...
                j == sNeedle.length() -1 ? iFoundPos = i + 1, j++ : j++; // all chars matching? Position begins at 0 instead 1, so "-1" and "+1"
        }
    }
    return iFoundPos;
}

string itos(unsigned long long i, unsigned short base) { // Integer zu String
    int len = 0, k = 1;
    unsigned long long j = i, div = 1;
    string s = "";
    if(base == 16) {
        unsigned short rest;
        string str = "", buchstabe = "ABCDEF";
        do { rest = i % 16, i /= 16, rest < 10 ? str += char(rest + 48) : str += buchstabe[rest - 10]; } while(i);
        for(i = str.length(); i > 0; i--) s += str[i-1];
    }
    else {
        for(; j; j /= base) len++;
        if(!len) len = 1;
        for(j = 1; j < len; j++) div *= base;
        for(j = len; j > 0; j--) k = i/div, i = i - (k * div), div /= base, s += char(k + 48);
    }
    return s;
}

int ctoi(char c) { // convert char to integer  (Example: c='d'; i=ctoi(c) --> i = 13   ,   s="13b6f"; i=ctoi(s[2])  -->  i = 11)
    if((c > 57) || c < 48) { // no decimal character
        if((c > 64) && (c < 71)) return c - 55; // A-F
        else if((c > 96) && (c < 103)) return c - 87; // a-f
        else return 0; // no hex character, so return 0
    }
    return c - 48;
}

string stringToUpper(string s) { // konvertiert alle Kleinbuchstaben zu Grossbuchstaben
    if(s.length()) { // if string not empty...
        for(int i = 0; i < s.length(); i++) { // check every char in string...
            if((int)s[i] > 96 && (int)s[i] < 123) // if char an lower case...
                s[i] -= 32; // sub 32, to convert to upper case
                            // replace german chars...
            else if((char)s[i] == (char) 'ä') s[i] = 'Ä';
            else if((char)s[i] == (char) 'ö') s[i] = 'Ö';
            else if((char)s[i] == (char) 'ü') s[i] = 'Ü';
        }
    }
    return s;
}

bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) {
    int i, zahl = 0, start = 0, nullPos = 0;
    string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2);    //Macht alles Groß, außer Sonderzeichen
    string strZahl;

    // Ersetze Soderzeichen mit "normalen" Großbuchstaben
    while(i = strPos("Ä", s1)) s1.replace(i-1, 2, "A");
    while(i = strPos("Ö", s1)) s1.replace(i-1, 2, "O");
    while(i = strPos("Ü", s1)) s1.replace(i-1, 2, "U");
    while(i = strPos("ä", s1)) s1.replace(i-1, 2, "A");
    while(i = strPos("ö", s1)) s1.replace(i-1, 2, "O");
    while(i = strPos("ü", s1)) s1.replace(i-1, 2, "U");
    while(i = strPos("ß", s1)) s1.replace(i-1, 2, "SS");
    while(i = strPos("Ä", s2)) s2.replace(i-1, 2, "A");
    while(i = strPos("Ö", s2)) s2.replace(i-1, 2, "O");
    while(i = strPos("Ü", s2)) s2.replace(i-1, 2, "U");
    while(i = strPos("ä", s2)) s2.replace(i-1, 2, "A");
    while(i = strPos("ö", s2)) s2.replace(i-1, 2, "O");
    while(i = strPos("ü", s2)) s2.replace(i-1, 2, "U");
    while(i = strPos("ß", s2)) s2.replace(i-1, 2, "SS");

    // 01234 ist größer als 45.
    // Darum:
    // 1. Führende Nullen entfernen
    // 2. Anzahl der Stellen voranstellen
    // 3. Danach kann wieder stelle für Stelle verglichen werden
    // Beispiel: aus 01234 wird "41234" , aus 45 wird "245"
    // ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung

    // Führende Nullen entfernen...

    for(i = 0, start = 1; nullPos = strPos("0", s1, start); i++) {
        // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen
        if(nullPos == s1.length()) start++;                    // Die Null ist am Ende, da soll sie bleiben.
        else if((nullPos == 1) && (s1[1] > 47 && s1[1] < 58))  // Das erste Zeichen ist eine Null, gefolgt von einer Zahl
            s1.erase(0, 1), i--;                                 // diese Null löschen
        else if(s1[nullPos-2] < 48 || s1[nullPos-2] > 57)      // Die Null kommt irgendwo ist String vor, davor ist keine Zahl
            s1.erase(nullPos-1, 1), i--;                         // diese Null löschen
        else start = nullPos + 1;                               // Die Suche eine Stelle weiter hinten fortsetzen
    }
    for(i = 0, start = 1; (nullPos = strPos("0", s2, start)) && (s2.length() > i); i++) {
        // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen
        if(nullPos == s2.length()) start++;                    // Die Null ist am Ende, da soll sie bleiben.
        else if((nullPos == 1) && (s2[1] > 47 && s2[1] < 58))  // Das erste Zeichen ist eine Null, gefolgt von einer Zahl
            s2.erase(0, 1), i--;                                 // diese Null löschen
        else if(s2[nullPos-2] < 48 || s2[nullPos-2] > 57)      // Die Null kommt irgendwo ist String vor, davor ist keine Zahl
            s2.erase(nullPos-1, 1), i--;                         // diese Null löschen
        else start = nullPos + 1;                               // Die Suche eine Stelle weiter hinten fortsetzen
    }

    // Anzahl der Zahlen voranstellen...
    zahl = 0;
    for(i = 0; i <= s1.length(); i++) {
        if(s1[i] > 47 && s1[i] < 58) {                         // Eine Zahl
            if(!zahl) zahl = ctoi(s1[i]);                      // Eine "neue" Zahl...
            else zahl = zahl * 10 + ctoi(s1[i]);                // Die Zahl geht weiter
        }
        else if(zahl) {                                        // Es ist keine Zahl mehr, aber es gab eine Zahl...
            strZahl = itos(zahl);                               // Die Zahl in einen String umwandeln
            strZahl = itos(strZahl.length()) + strZahl;         // Die Anzahl der Stellen voranstellen
            s1 = s1.substr(0, i+1-strZahl.length()) + strZahl + s1.substr(i); // Die Zahl ersetzen
            zahl = 0;
        }
    }
    zahl = 0;
    for(i = 0; i <= s2.length(); i++) {
        if(s2[i] > 47 && s2[i] < 58) {                         // Eine Zahl
            if(!zahl) zahl = ctoi(s2[i]);                      // Eine "neue" Zahl...
            else zahl = zahl * 10 + ctoi(s2[i]);                // Die Zahl geht weiter
        }
        else if(zahl) {                                        // Es ist keine Zahl mehr, aber es gab eine Zahl...
            strZahl = itos(zahl);                               // Die Zahl in einen String umwandeln
            strZahl = itos(strZahl.length()) + strZahl;         // Die Anzahl der Stellen voranstellen
            s2 = s2.substr(0, i+1-strZahl.length()) + strZahl + s2.substr(i); // Die Zahl ersetzen
            zahl = 0;
        }
    }
    return (reverse ? s1 > s2 : s1 < s2);
}

void inventur() {
    // gesamte Datei einlesen und in der globalen Variable "ini" speichern (vektor mit 3 Strings)
    string str = "", bezeichnung = "", fach = "", menge = "";
    ifstream fin("Lager.ini");
    while(getline(fin, str)) {
        if(strPos("[", str) == 1 && strPos("]", str) == str.length()) {              // Kategorie gefunden
            if(bezeichnung.length())                                               // Nächster Eintrag (ansonsten erster Eintrag)
                bezeichnung = "", fach = "", menge = "";                            // Variablen löschen für nächsten Eintrag
            str = str.erase(0, 1);                                                  // Das "[" am Anfang entfernen
            str = str.erase(str.length()-1, 1);                                     // Das "]" am Ende entfernen
            bezeichnung = str;                                                      // "bezeichnung" enthält nun die Kategorie
        }
        if(strPos("Fach_", str) == 1)                                               // Wenn "Fach_x=", dann vorne (inkl. "=") abschneiden
            fach = str.erase(0, strPos("=", str));
        else if(strPos("Menge_", str) == 1)                                         // Wenn "Menge_x=", dann vorne (inkl. "=") abschneiden
            ini.push_back({bezeichnung,fach,str.erase(0,strPos("=",str))});
    }
    fin.close();
}

void liveSuche() {
    // Die Listbox muss mit jedem Zeichen neu erstellt werden
    p_listboxLager->auto_draw(false);              // Auto-Draw deaktivieren (geht schneller und vermeidet "flackern")
    p_listboxLager->clear();                       // die Listbox komplett leeren

    int index = 0;
    string suche = p_textboxSuchen->caption();     // den Inhalt der TB als Suchstring benutzen

    for(vector<iniInhalt>::const_iterator i = ini.begin(); i!=ini.end(); ++i) {
        if(strPos(stringToUpper(suche), stringToUpper(ini[index].b)) || suche.length() == 0)
            p_listboxLager->at(0).append({ini[index].b, ini[index].f , ini[index].m});     // Einen Eintrag in die Listbox hinzufügen
        index++;
    }
    p_listboxLager->sort_col(2), p_listboxLager->sort_col(1), p_listboxLager->sort_col(0); // Sortierung Spalte 1, dann Spalte 2, dann Spalte 3
    p_listboxLager->auto_draw(true);
}

void bearbeiten() {
    form fmBearbeiten(*p_fm, rectangle(-5, -25, 520, 350), appear::decorate<appear::minimize>());
    fmBearbeiten.caption("Lager bearbeiten");                                               // Fenstertitel
                                                                                            // ------------------------------------- Icon  -------------------------------------
    wstring app_path(4096, '\0');                                                           // Speichert den Pfad des ausgeführten Programms
    app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size()));             // Passt die Groesse an
    fmBearbeiten.icon(paint::image(app_path));
    fmBearbeiten.bgcolor(color_rgb(bgc));                                                   // Hintergrundfarbe

                                                                                            // Steuerelemente erstellen
    textbox textboxNeuBezeichnung(fmBearbeiten, rectangle(10, 33, 300, 22));            // Textbox Bezeichnung

                                                                                        // Steuerelemente einrichten
    textboxNeuBezeichnung.caption(lastSelect.b);

    // Fenster verschieben durch Kopfzeile
    fmBearbeiten.events().move([fmBearbeiten](const arg_move& arg) {
        p_fm->move(arg.x, arg.y-25);
    });

    // Fenster verschieben durch Hintergrund
    dragger dg;
    dg.target(*p_fm);
    dg.target(fmBearbeiten);
    dg.trigger(fmBearbeiten);

    fmBearbeiten.modality();
}

Btw, when I double click in the listbox on a selected row, so "lastselect.b" is empty. I found solution (lastSelectBefore), but this solution is not the best way. Do you have a better Idea?

I don't have time to look into this right now, but maybe in a few hours. smile

You can just declare some global pointers, and assign to them the object addresses in the main. Then, use the pointers in your functions: ```` #include <fstream> // fuer Dateibehandlungen // #include <stdlib.h> // fuer Zufall #include <string.h> // fuer Strings // #include <time.h> // fuer Zufall #include <vector> // für Vektoren (dynamische Arrays) #include <windows.h> // fuer Windows-Funktionen #include<nana/gui/dragger.hpp> // Drag & Drop #include <nana/gui/wvl.hpp> // Nana Klasswendefinition #include <nana/gui/msgbox.hpp> // fuer Message-Boxen // #include <nana/gui/timer.hpp> // fuer Timer #include <nana/gui/tooltip.hpp> // fuer Tooltips #include <nana/gui/widgets/button.hpp> // fuer Buttons // #include <nana/gui/widgets/checkbox.hpp> // fuer Check-Boxen // #include <nana/gui/widgets/group.hpp> // fuer Gruppen #include <nana/gui/widgets/label.hpp> // fuer Label #include <nana/gui/widgets/listbox.hpp> // fuer Listbox // #include <nana/gui/widgets/slider.hpp> // fuer Slider #include <nana/gui/widgets/textbox.hpp> // fuer Text-Boxen // Namespaces using namespace std; using namespace nana; // Globale Variablen //{ int bgc = 0xF4F4FB; // Hintergrundfarbe struct iniInhalt { string b, f, m; }; // Eine Struktur für den Lagerinhalt vector<iniInhalt> ini; // Eine Variable des Types iniInhalt iniInhalt lastSelect = {"","",""}; // letzte Auswahl in der Listbox iniInhalt lastSelectBefore = {"","",""}; // vorletzte Auswahl in der Listbox (fuer Doppelklick) //} // Deklarationen //{ int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0); // Vereinfachte Erstellung einer MessageBox int strPos(string sNeedle, string sHaystack, int iStartPos = 1); // Ermittelt die Position in einem String string itos(unsigned long long i, unsigned short base = 10); // Macht aus Zahlen Strings int ctoi(char c); // Wandelt String-Zahlen in Integer-Zahlen string stringToUpper(string s); // Wandelt alles in Großbuchstaben bool sort_compare_insensitive(const string& s1, any*, const string& s2, any*, bool reverse); // Sortiert alphabetisch (ohne Groß-Kein-Unterscheidung) void inventur(); // Gibt den gesamten Lagerbestand zurück. void liveSuche(); // Prüft ob der Suchtext in der Listbox vorhanden ist void bearbeiten(); // zum bearbeiten/hinzufügen eines Eintrages //} // ************************************* GUI erstellen ************************************** // --------------------- Fenster und Steuerelemente erstellen (global) ---------------------- //{ // Fenster erstellen listbox *p_listboxLager{nullptr}; textbox *p_textboxSuchen{nullptr}; form *p_fm{nullptr}; //} int main() { form fm(API::make_center(520, 350), appear::decorate<appear::minimize>()); p_fm = &fm; // Steuerelemente erstellen label labelSuchen(fm, rectangle(10, 10, 200, 22)); // Label Suchen textbox textboxSuchen(fm, rectangle(10, 33, 300, 22)); // Textbox Suchen p_textboxSuchen = &textboxSuchen; listbox listboxLager(fm, rectangle(10, 70, 500, 180)); // Listbox Lager p_listboxLager = &listboxLager; button buttonNeu(fm, rectangle(10, 300, 120, 30)); // Button Bearbeiten button buttonBeenden(fm, rectangle(150, 300, 120, 30)); // Button Beenden label debug(fm, rectangle(300, 300, 210, 30)); // Das Fenster verschiebbar machen, indem man einfach ins Fenster klickt und die Maus zieht. dragger dgMain; dgMain.target(fm); dgMain.trigger(fm); // ------------------------------------- Icon ------------------------------------- wstring app_path(4096, '\0'); // Speichert den Pfad des ausgeführten Programms app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size())); // Passt die Groesse an fm.icon(paint::image(app_path)); // Verwendet das Icon der EXE (dieses ist per Recource festgelegt) // ----------------------------- Variablen deklarieren ----------------------------- string str; // für temporaere Strings string lagerIni; // Lädt den gesamten Lagerbestand in die Variable // ------------------------- Steuerelemente "einrichten" --------------------------- // Fenster fm.caption("Store Manager v1.0"); // Fenstertitel fm.bgcolor(color_rgb(bgc)); // Hintergrundfarbe // Label Suchen labelSuchen.bgcolor(color_rgb(bgc)); // Hintergrundfarbe labelSuchen.format(true); // Ermoeglicht HTML-Formatierung labelSuchen.caption({ // Text "Comic Sans MS" "<size=12, bold=false, font=\"Comic Sans MS\">Suche nach:</>"}); labelSuchen.tooltip("Wonach gesucht werden soll..."); // Tooltip // Textbox Suchen textboxSuchen.multi_lines(false); // Nur eine Zeile erlaubt textboxSuchen.typeface(paint::font{"Comic Sans MS", 10}); // Schrift und Schriftgroesse textboxSuchen.focus(); // Setzt den Focus textboxSuchen.events().text_changed(liveSuche); // Ruft die Live-Suche auf textboxSuchen.events().key_char([&textboxSuchen](const arg_keyboard& arg) { // Event Taste if(arg.key == keyboard::enter) mbox("Fehlt noch!"); // Wenn Enter ... // hier sollte nun in das nächste Suchfeld gesprungen werden }); // Listbox Lager listboxLager.enable_single(true, 1); // Erlaubt nur eine Auswahl (keine Mehrfachauswahl) listboxLager.typeface(paint::font{"Comic Sans MS", 10}); // Schrift und Schriftgroesse für die Listbox listboxLager.append_header("Bezeichnung", 180); // Spalte "Bezeichnung" listboxLager.append_header("Lagerort", 230); // Spalte "Lagerort" listboxLager.append_header("Menge", 65); // Spalte "Menge" listboxLager.column_at(0).typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse für die Überschrift der Spalte 0 listboxLager.column_at(1).typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse für die Überschrift der Spalte 1 listboxLager.column_at(2).typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse für die Überschrift der Spalte 2 listboxLager.sortable(true); listboxLager.auto_draw(false); listboxLager.set_sort_compare(0, sort_compare_insensitive); // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung listboxLager.set_sort_compare(1, sort_compare_insensitive); // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung listboxLager.set_sort_compare(2, sort_compare_insensitive); // Sortierung: Alphabetisch ohne Groß-Klein-Unterscheidung inventur(); // Liest die Daten aus der INI-Datei liveSuche(); // Filtert die Listbox nach dem Suchstring listboxLager.auto_draw(true); listboxLager.events().selected([&listboxLager](const arg_listbox& arg) { if(arg.item.selected()) { lastSelect = {arg.item.text(0),arg.item.text(1),arg.item.text(2)}; if(lastSelect.b != "") lastSelectBefore = lastSelect; // beim Doppelklick wird markiert/demarkiert } else lastSelect = {}; }); listboxLager.events().dbl_click([&listboxLager](const arg_mouse &arg) { // beim Doppelklick merken wo die Maus steht if(!listboxLager.cast(arg.pos).empty()) { // Wenn die auf einen Eintrag steht... if(lastSelect.b == "") lastSelect = lastSelectBefore; bearbeiten(); } }); listboxLager.events().key_char([&listboxLager](const arg_keyboard& arg) { // Event Taste Enter if((arg.key == keyboard::enter) && (lastSelect.b != "")) bearbeiten(); // Wenn Enter bei selektierter Listbox --> ... }); // Button Neu buttonNeu.typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse buttonNeu.caption("Neuer Eintrag"); // Beschriftung des Button //buttonNeu.caption((wstring)charset("Neuer Eintrag")); // Beschriftung des Button (in UTF-8) buttonNeu.enable_focus_color(false); // Die "Fokus-Farbe" deaktivieren buttonNeu.events().click([&buttonNeu]() { bearbeiten(); }); // Event: Click LM buttonNeu.events().key_char([&buttonNeu](const arg_keyboard& arg) { // Event Taste Enter if(arg.key == keyboard::enter) bearbeiten(); // Wenn Enter bei focusierten Button --> ... }); // Button Beenden buttonBeenden.typeface(paint::font{"Comic Sans MS", 12}); // Schrift und Schriftgroesse buttonBeenden.caption("Beenden"); // Beschriftung des Button buttonBeenden.enable_focus_color(false); // Die "Fokus-Farbe" deaktivieren buttonBeenden.events().click(API::exit_all); // Event: Click LM buttonBeenden.events().key_char([&buttonBeenden](const arg_keyboard& arg) { // Event Taste Enter if(arg.key == keyboard::enter) API::exit_all(); // Wenn Enter bei focusierten Button --> Programm schließen }); // GUI anzeigen fm.show(); // GUI sichtbar machen exec(); // Endlosschleife bis die GUI zerstoert wird (warten auf Ereignisse) return 0; } int mbox(string inhalt, string titel, unsigned short art, unsigned short symbol, window fenster) { // Vereinfachte Erstellung einer MessageBox // int mbox(string inhalt = "", string titel = "", unsigned short art = 0, unsigned short symbol = 0, window fenster = 0) { // MessageBox mit Nana // mbox([Inhalt],[Titel],[Buttons(0-2)],[Icon(0-4)],[owner]) // ---- Bedeutung der Werte ---- // Buttons: 0 = OK , 1 = Ja + Nein , 2 = Ja + Nein + Abbrechen // Icons: 0 = Ohne Icon , 1 = Information , 2 = Warnung , 3 = Fehler , 4 = Frage // Auswahl: 0 = Abbruch , 1 = OK , 2 = Ja , 3 = Nein unsigned short auswahl; msgbox::button_t buttons; switch(art) { // Buttonauswahl case 1: buttons = msgbox::yes_no; break; case 2: buttons = msgbox::yes_no_cancel; break; default: buttons = msgbox::ok; break; } msgbox m(fenster, titel, buttons); // Die Messagebox erstellen m << inhalt; // Den Inhalt (Text) einfuegen switch(symbol) { // Ein Icon hinzufuegen case 1: m.icon(m.icon_information); break; case 2: m.icon(m.icon_warning); break; case 3: m.icon(m.icon_error); break; case 4: m.icon(m.icon_question); break; } auto response = m(); // Auf eine Auswahl warten switch(response) { // Die Auswahl als Integer zurueckliefern case m.pick_ok: auswahl = 1; break; case m.pick_yes: auswahl = 2; break; case m.pick_no: auswahl = 3; break; default: auswahl = 0; break; } return auswahl; } int strPos(string sNeedle, string sHaystack, int iStartPos) { // needs #include <string> // search needle in haystack unsigned short iFoundPos = 0, j; // if haystack >= needle... if(sHaystack.length() >= sNeedle.length()) { // while haystack is big enough to contain the needle ... for(int i = iStartPos -1; (sHaystack.length() >= i + sNeedle.length()) && !iFoundPos; i++) { j = 0; // always begin at the first character in haystack (= position 0) while(sHaystack[i + j] == sNeedle[j]) // matching the next char, and the next ... j == sNeedle.length() -1 ? iFoundPos = i + 1, j++ : j++; // all chars matching? Position begins at 0 instead 1, so "-1" and "+1" } } return iFoundPos; } string itos(unsigned long long i, unsigned short base) { // Integer zu String int len = 0, k = 1; unsigned long long j = i, div = 1; string s = ""; if(base == 16) { unsigned short rest; string str = "", buchstabe = "ABCDEF"; do { rest = i % 16, i /= 16, rest < 10 ? str += char(rest + 48) : str += buchstabe[rest - 10]; } while(i); for(i = str.length(); i > 0; i--) s += str[i-1]; } else { for(; j; j /= base) len++; if(!len) len = 1; for(j = 1; j < len; j++) div *= base; for(j = len; j > 0; j--) k = i/div, i = i - (k * div), div /= base, s += char(k + 48); } return s; } int ctoi(char c) { // convert char to integer (Example: c='d'; i=ctoi(c) --> i = 13 , s="13b6f"; i=ctoi(s[2]) --> i = 11) if((c > 57) || c < 48) { // no decimal character if((c > 64) && (c < 71)) return c - 55; // A-F else if((c > 96) && (c < 103)) return c - 87; // a-f else return 0; // no hex character, so return 0 } return c - 48; } string stringToUpper(string s) { // konvertiert alle Kleinbuchstaben zu Grossbuchstaben if(s.length()) { // if string not empty... for(int i = 0; i < s.length(); i++) { // check every char in string... if((int)s[i] > 96 && (int)s[i] < 123) // if char an lower case... s[i] -= 32; // sub 32, to convert to upper case // replace german chars... else if((char)s[i] == (char) 'ä') s[i] = 'Ä'; else if((char)s[i] == (char) 'ö') s[i] = 'Ö'; else if((char)s[i] == (char) 'ü') s[i] = 'Ü'; } } return s; } bool sort_compare_insensitive(const string& s_1, any*, const string& s_2, any*, bool reverse) { int i, zahl = 0, start = 0, nullPos = 0; string s1 = stringToUpper(s_1), s2 = stringToUpper(s_2); //Macht alles Groß, außer Sonderzeichen string strZahl; // Ersetze Soderzeichen mit "normalen" Großbuchstaben while(i = strPos("Ä", s1)) s1.replace(i-1, 2, "A"); while(i = strPos("Ö", s1)) s1.replace(i-1, 2, "O"); while(i = strPos("Ü", s1)) s1.replace(i-1, 2, "U"); while(i = strPos("ä", s1)) s1.replace(i-1, 2, "A"); while(i = strPos("ö", s1)) s1.replace(i-1, 2, "O"); while(i = strPos("ü", s1)) s1.replace(i-1, 2, "U"); while(i = strPos("ß", s1)) s1.replace(i-1, 2, "SS"); while(i = strPos("Ä", s2)) s2.replace(i-1, 2, "A"); while(i = strPos("Ö", s2)) s2.replace(i-1, 2, "O"); while(i = strPos("Ü", s2)) s2.replace(i-1, 2, "U"); while(i = strPos("ä", s2)) s2.replace(i-1, 2, "A"); while(i = strPos("ö", s2)) s2.replace(i-1, 2, "O"); while(i = strPos("ü", s2)) s2.replace(i-1, 2, "U"); while(i = strPos("ß", s2)) s2.replace(i-1, 2, "SS"); // 01234 ist größer als 45. // Darum: // 1. Führende Nullen entfernen // 2. Anzahl der Stellen voranstellen // 3. Danach kann wieder stelle für Stelle verglichen werden // Beispiel: aus 01234 wird "41234" , aus 45 wird "245" // ...somit stimmt die Reihenfolge wieder, bei der Zeichen für Zeichen Sortierung // Führende Nullen entfernen... for(i = 0, start = 1; nullPos = strPos("0", s1, start); i++) { // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen if(nullPos == s1.length()) start++; // Die Null ist am Ende, da soll sie bleiben. else if((nullPos == 1) && (s1[1] > 47 && s1[1] < 58)) // Das erste Zeichen ist eine Null, gefolgt von einer Zahl s1.erase(0, 1), i--; // diese Null löschen else if(s1[nullPos-2] < 48 || s1[nullPos-2] > 57) // Die Null kommt irgendwo ist String vor, davor ist keine Zahl s1.erase(nullPos-1, 1), i--; // diese Null löschen else start = nullPos + 1; // Die Suche eine Stelle weiter hinten fortsetzen } for(i = 0, start = 1; (nullPos = strPos("0", s2, start)) && (s2.length() > i); i++) { // es kommt eine Null im String vor und diese ist nicht das letzte Zeichen if(nullPos == s2.length()) start++; // Die Null ist am Ende, da soll sie bleiben. else if((nullPos == 1) && (s2[1] > 47 && s2[1] < 58)) // Das erste Zeichen ist eine Null, gefolgt von einer Zahl s2.erase(0, 1), i--; // diese Null löschen else if(s2[nullPos-2] < 48 || s2[nullPos-2] > 57) // Die Null kommt irgendwo ist String vor, davor ist keine Zahl s2.erase(nullPos-1, 1), i--; // diese Null löschen else start = nullPos + 1; // Die Suche eine Stelle weiter hinten fortsetzen } // Anzahl der Zahlen voranstellen... zahl = 0; for(i = 0; i <= s1.length(); i++) { if(s1[i] > 47 && s1[i] < 58) { // Eine Zahl if(!zahl) zahl = ctoi(s1[i]); // Eine "neue" Zahl... else zahl = zahl * 10 + ctoi(s1[i]); // Die Zahl geht weiter } else if(zahl) { // Es ist keine Zahl mehr, aber es gab eine Zahl... strZahl = itos(zahl); // Die Zahl in einen String umwandeln strZahl = itos(strZahl.length()) + strZahl; // Die Anzahl der Stellen voranstellen s1 = s1.substr(0, i+1-strZahl.length()) + strZahl + s1.substr(i); // Die Zahl ersetzen zahl = 0; } } zahl = 0; for(i = 0; i <= s2.length(); i++) { if(s2[i] > 47 && s2[i] < 58) { // Eine Zahl if(!zahl) zahl = ctoi(s2[i]); // Eine "neue" Zahl... else zahl = zahl * 10 + ctoi(s2[i]); // Die Zahl geht weiter } else if(zahl) { // Es ist keine Zahl mehr, aber es gab eine Zahl... strZahl = itos(zahl); // Die Zahl in einen String umwandeln strZahl = itos(strZahl.length()) + strZahl; // Die Anzahl der Stellen voranstellen s2 = s2.substr(0, i+1-strZahl.length()) + strZahl + s2.substr(i); // Die Zahl ersetzen zahl = 0; } } return (reverse ? s1 > s2 : s1 < s2); } void inventur() { // gesamte Datei einlesen und in der globalen Variable "ini" speichern (vektor mit 3 Strings) string str = "", bezeichnung = "", fach = "", menge = ""; ifstream fin("Lager.ini"); while(getline(fin, str)) { if(strPos("[", str) == 1 && strPos("]", str) == str.length()) { // Kategorie gefunden if(bezeichnung.length()) // Nächster Eintrag (ansonsten erster Eintrag) bezeichnung = "", fach = "", menge = ""; // Variablen löschen für nächsten Eintrag str = str.erase(0, 1); // Das "[" am Anfang entfernen str = str.erase(str.length()-1, 1); // Das "]" am Ende entfernen bezeichnung = str; // "bezeichnung" enthält nun die Kategorie } if(strPos("Fach_", str) == 1) // Wenn "Fach_x=", dann vorne (inkl. "=") abschneiden fach = str.erase(0, strPos("=", str)); else if(strPos("Menge_", str) == 1) // Wenn "Menge_x=", dann vorne (inkl. "=") abschneiden ini.push_back({bezeichnung,fach,str.erase(0,strPos("=",str))}); } fin.close(); } void liveSuche() { // Die Listbox muss mit jedem Zeichen neu erstellt werden p_listboxLager->auto_draw(false); // Auto-Draw deaktivieren (geht schneller und vermeidet "flackern") p_listboxLager->clear(); // die Listbox komplett leeren int index = 0; string suche = p_textboxSuchen->caption(); // den Inhalt der TB als Suchstring benutzen for(vector<iniInhalt>::const_iterator i = ini.begin(); i!=ini.end(); ++i) { if(strPos(stringToUpper(suche), stringToUpper(ini[index].b)) || suche.length() == 0) p_listboxLager->at(0).append({ini[index].b, ini[index].f , ini[index].m}); // Einen Eintrag in die Listbox hinzufügen index++; } p_listboxLager->sort_col(2), p_listboxLager->sort_col(1), p_listboxLager->sort_col(0); // Sortierung Spalte 1, dann Spalte 2, dann Spalte 3 p_listboxLager->auto_draw(true); } void bearbeiten() { form fmBearbeiten(*p_fm, rectangle(-5, -25, 520, 350), appear::decorate<appear::minimize>()); fmBearbeiten.caption("Lager bearbeiten"); // Fenstertitel // ------------------------------------- Icon ------------------------------------- wstring app_path(4096, '\0'); // Speichert den Pfad des ausgeführten Programms app_path.resize(GetModuleFileNameW(0, &app_path.front(), app_path.size())); // Passt die Groesse an fmBearbeiten.icon(paint::image(app_path)); fmBearbeiten.bgcolor(color_rgb(bgc)); // Hintergrundfarbe // Steuerelemente erstellen textbox textboxNeuBezeichnung(fmBearbeiten, rectangle(10, 33, 300, 22)); // Textbox Bezeichnung // Steuerelemente einrichten textboxNeuBezeichnung.caption(lastSelect.b); // Fenster verschieben durch Kopfzeile fmBearbeiten.events().move([fmBearbeiten](const arg_move& arg) { p_fm->move(arg.x, arg.y-25); }); // Fenster verschieben durch Hintergrund dragger dg; dg.target(*p_fm); dg.target(fmBearbeiten); dg.trigger(fmBearbeiten); fmBearbeiten.modality(); } ```` > Btw, when I double click in the listbox on a selected row, so "lastselect.b" is empty. I found solution (lastSelectBefore), but this solution is not the best way. Do you have a better Idea? I don't have time to look into this right now, but maybe in a few hours. :)
edited Oct 9 '18 at 8:03 pm

Wow, thanks.
I´m a beginner. Pointer is a new section for me, but it looks good.
I´m very thankful, that you help me and give hints to my faults.
I will read some about pointers, to understand it better. You version with pointers works great, so I will it use instead my "global" version smile

Wow, thanks. I´m a beginner. Pointer is a new section for me, but it looks good. I´m very thankful, that you help me and give hints to my faults. I will read some about pointers, to understand it better. You version with pointers works great, so I will it use instead my "global" version ;)

...because I need to change from functions.

My suggestion is to make a class and write the functions that access the widgets as member functions of the class.

>...because I need to change from functions. My suggestion is to make a class and write the functions that access the widgets as member functions of the class.

Uhhh, I´m a beginner. My programming experience ends by functions smile .
I have learned the "struct" only recently here by programming with nana smile .
I want to learn it, but I want to complete my programm soon.
But in future, I will learn to programming with classes ...promised smile

Uhhh, I´m a beginner. My programming experience ends by functions :D . I have learned the "struct" only recently here by programming with nana (wasntme) . I want to learn it, but I want to complete my programm soon. But in future, I will learn to programming with classes ...promised :)
edited Oct 10 '18 at 9:16 pm

Btw, when I double click in the listbox on a selected row, so "lastselect.b" is empty. I found solution (lastSelectBefore), but this solution is not the best way. Do you have a better Idea?

You could suppress the listbox behavior of deselecting an item when clicked, like this:

    listboxLager.events().mouse_down([&listboxLager](const arg_mouse &arg)
    {
        auto idx_pair{listboxLager.cast(arg.pos)};
        if(!idx_pair.empty())
        {
            auto item_idx{listboxLager.at(idx_pair.cat).index_cast(idx_pair.item, true)};
            auto item{listboxLager.at(idx_pair.cat).at(item_idx)};
            item.select(true);
        }
    });

I don't know if you find that desirable, but it would eliminate this whole headache.

> Btw, when I double click in the listbox on a selected row, so "lastselect.b" is empty. I found solution (lastSelectBefore), but this solution is not the best way. Do you have a better Idea? You could suppress the `listbox` behavior of deselecting an item when clicked, like this: ```` listboxLager.events().mouse_down([&listboxLager](const arg_mouse &arg) { auto idx_pair{listboxLager.cast(arg.pos)}; if(!idx_pair.empty()) { auto item_idx{listboxLager.at(idx_pair.cat).index_cast(idx_pair.item, true)}; auto item{listboxLager.at(idx_pair.cat).at(item_idx)}; item.select(true); } }); ```` I don't know if you find that desirable, but it would eliminate this whole headache.
edited Oct 10 '18 at 11:43 pm
12
214
views
38
replies
4
followers
live preview
enter atleast 10 characters
WARNING: You mentioned %MENTIONS%, but they cannot see this message and will not be notified
Saving...
Saved
All posts under this topic will be deleted ?
Pending draft ... Click to resume editing
Discard draft