|  | Home · Overviews · Examples

# Qt Jambi Tutorial 7 - One Thing Leads to Another

This example shows how to create custom widgets with signals and slots, and how to connect them together in more complex ways.

## Line by Line Walkthrough

This file is mainly lifted from `BlocksGalore` in Chapter 6; only the non-trivial changes are noted here.

The LCDRange class now includes three members besides the constructor. They make up an interface between this widget and other components in a program. Until now, `LCDRange` didn't really have an API at all. We will examine them as we stumble upon them in the code.

This class is for the most part equal to LCDRange from chapter 6, and only the changes are noted here.

            quit.setFont(new QFont("Times", 18, QFont.Weight.Bold.value()));

We have added a private variable that will hold the number in the display.

            public final Signal1<Integer> valueChanged = new Signal1<Integer>();

Here we declare our first custom signal: `valueChanged`. We will emit it whenever the value of the LCD changes. A signal is an instance of one of the signal classes, which are Signal1, Signal2 ... Signal9). The suffix number is equal to the number of arguments of the signal; the types of the arguments must be given as class generics. We want one argument (the value of the LCD display), so we use the Signal1 class with Integers. You already know how to connect to the signal. The signal can be connected to any method that takes an Integer.

We move on to the constructor:

            public LCDRange()

            {
    ...

12

                slider.valueChanged.connect(lcd, "display(int)");

                slider.valueChanged.connect(valueChanged);
    ...

12

            }

We connect the sliders `valueChanged` signal to our `display()` slot, and to our own `valueChanged` signal. The signal you connect will be triggered by the signal to which it is connected.

Let's take a closer look at what happens when the user operates the slider. The slider sees that its value has changed and emits the QSlider.valueChanged signal. That signal is connected both to the QLCDNumber.display() slot and to the `valueChanged` signal of the `LCDRange`.

Thus, when the signal is emitted, `LCDRange` emits its own `valueChanged` signal. In addition, QLCDNumber.display() is called and shows the new number.

Note that you're not guaranteed any particular order of execution; `LCDRange.valueChanged` may be emitted before or after QLCDNumber.display() is called.

            public int value()
            {
                return value;
            }

The implementation of `value()` is straightforward. It simply returns the slider's value.

            public void setValue(int value)
            {
                slider.setValue(value);
            }

The implementation of `setValue()` is equally straightforward. Note that because the slider and LCD number are connected, setting the slider's value automatically updates the LCD number as well. In addition, the slider will automatically adjust the value if it is outside its legal range.

The `ConnectedSlider` class is copied from BlocksGalore in the previous chapter except for the constructor. We examine the changes here:

            LCDRange previousRange = null;

            for (int row = 0; row < 3; ++row) {
                for (int column = 0; column < 3; ++column) {
                    LCDRange lcdRange = new LCDRange();
                    grid.addWidget(lcdRange, row, column);

                if (previousRange != null)
                    lcdRange.valueChanged.
                    connect(previousRange, "setValue(int)");

                    previousRange = lcdRange;

                }

            }

When we create the nine `LCDRange` objects, we connect them using the signals and slots mechanism. Each has its `valueChanged` signal connected to the previous one's `setValue()` slot. Because `LCDRange` emits the `valueChanged` signal when its value changes, we are here creating a chain of signals and slots.

## Running the Application

On startup, the program's appearance is identical to the previous one. Try operating the slider to the bottom-right.

## Exercises

Use the bottom-right slider to set all LCDs to 50. Then set the top six to 30 by clicking on the slider on the row above. Now, use the one to the left of the last one operated to set the first five LCDs back to 50.

Click to the left of the handle on the bottom-right slider. What happens? Why is this the correct behavior?