Skip to content

Table Filter

tpecholt edited this page Jul 31, 2023 · 2 revisions

UPDATED 07/31/23

Here we demonstrate basic data binding and filtering with the Table widget.

Creating a Window

Create a main window "Customer List" (see Window Types for more info). Save it as table_dlg.h.

  1. In the first row insert Text widget "Name" and Input widget for table filtering. Set the Input widget's type to std::string, rename fieldName to "filter" and set its keyboardFocus.

  2. Insert a Table widget below and set its size_x = -1, size_y = -1 to make it take all available space. Using the columns ... button define three columns "No.", "Name" and "Address". Make the last column stretchable.

You should see a picture similar to this:

image


Adding fields

Next we will create dialog's fields. Inspect the Class Wizard and see filter variable is declared. ImRAD created this variable at the time of inserting the Input widget and it will hold the widget's value. This is an example of a two-way variable binding - if you assign to filter variable in code it will appear in the widget as well and when user gives a new input that will be also assigned to the variable. In ImRAD two way bindings are usually managed by widget properties having the violet background.

For the table data we need to create a new field holding it. Open Class Wizard by pressing the toolbar button and add std::vector<Customer> data. Because we made a use of a new struct we need to define it. Create a new struct Customer by pressing the New struct... option from the drop down menu. Add name and address fields of type std::string into it.

image image


Table data binding

Insert 3 new Text widgets into the table. Set nextColumn = 1 for the second and third widget so they move to the subsequent columns. You may need to set their spacing back to 0 so they don't create a gap above.

After that set their text properties so that they bind to our variables. You can type the expression directly in the property or click the square button on right to do it in the binding dialog. Because the text property is a string value we need to put the variables inside {} brackets. Variable binding with formatting flags is also possible. You can add a dependency to popular fmt library and compile your app with IMRAD_WITH_FMT but this is not needed here.

In this case we configured a one-way binding. The GUI gets updated from your variables but because we used Text widgets user is not able to change the texts.

  1. text = {i+1}. By entering this expression you refer to the table's row variable i. Generated code will increment this variable for each row. Because the variable starts at 0 we +1

  2. text = {data[i].name}. Here we are referring to the name field of the Customer struct.

  3. text = {data[i].address}. Here we are referring to the address field of the Customer struct.

Next we need to tell the Table widget how many rows it contains. Set the rowCount property to data.size(). If you inspect the generated code you will see a for cycle is generated.

The dialog now looks like this:

image

Finally setup table filtering. Table widget has a rowFilter property for that. Here you can enter any valid C++ expression which when evaluates to false will cause the row to be skipped. We want to filter based on the name pattern so try this filter:

data[i].name.find(filter) != std::string::npos

Unfortunately std::string doesn't provide case insensitive comparison but it's enough to demonstrate how it works. You can use boost::ifind_first or any other function if that's available in your app.

Later try to use a special filtering widget which is also supported by ImRAD - change Input's type to ImGuiTextFilter. Then use following rowFilter expression:

filter.PassFilter(data[i].name.c_str())

this will do case insensitive comparison and supports multiple patterns (with ,) and exclusions (with -) as well.


First Run

Save the dialog and use it in your app as usual. Initialize the data dialog variable with some test data before first use:

tableDlg.data = {
                { "Jan Luc", "Paris, France" },
		{ "Dimitrij Kukov", "Kharkov, Ukraine" },
		{ "Hans Voegel", "Hamburg, Germany" },
		{ "Karel Hora", "Prague, Czechia" },
		{ "Pierre Liguere", "Rome, Italy" },
		{ "Adolf Schatz", "Wien, Austria" }
	}; 

You can test the app to see filtering works and we didn't even need to write any logic for that!

image

Clone this wiki locally