Project

General

Profile

WCombo Box Mysteriously Grows Taller

Added by Ben Jackson over 11 years ago

I'm using a WComboBox inside a WGridLayout inside a WDialog. I add two items to the box explicitly when it is created. It works fine, but when I make a call like this:

combo->setCurrentIndex(0);
triggerUpdates();

the box gets about two pixels taller for some reason. The index is correctly set, and everything else works fine.

Any guess why this might happen?


Replies (7)

RE: WCombo Box Mysteriously Grows Taller - Added by Koen Deforche over 11 years ago

Hey,

This sounds like a typical layout manager problem.

What version of Wt, browser and browser host OS is this ?

Regards,

Koen

RE: WCombo Box Mysteriously Grows Taller - Added by Ben Jackson over 11 years ago

The browser host is Windows Vista. The behavior occurs in Chrome 22, but not in Firefox 16 or IE 9. Wt version is 3.2.1 The server is running Ubuntu 11.10.

Ben

RE: WCombo Box Mysteriously Grows Taller - Added by Koen Deforche over 11 years ago

Hey Ben,

I would like to reproduce this. Would it be easy for you to generate a test-case ?

Somehow, you must be having a layout where the combo-box is in a row with other (taller) items, so be sure to include those.

As a workaround, if you do not really want the combo-box to be vertically stretched, you can add the combo box with an AlignTop or AlignMiddle alignment flag.

Regards,

koen

RE: WCombo Box Mysteriously Grows Taller - Added by Ben Jackson over 11 years ago

I distilled it down to a (somewhat) simple example that shows:

Behavior 1: in Chrome 22, the first time an update is triggered, both input fields get a few pixels taller.

Behavior 2: in Firefox 16, EVERY time an update is triggered, both input fields get a few pixels taller. This behavior is new in the example code, and doesn't happen in my main application.

In IE 9 there is no height problem, but the width of the input fields doesn't align. (not sure if it should)

The goal of this code is just to keep the input fields in sync across all open sessions. It doesn't actually initialize the values correctly in this example, but if you have two windows open, changes in one should appear in the other.

#include <boost/noncopyable.hpp>
#include <Wt/WSignal>
#include <Wt/WString>
#include <Wt/WServer>
#include <Wt/WApplication>
#include <Wt/WDialog>
#include <Wt/WGridLayout>
#include <Wt/WComboBox>
#include <Wt/WSpinBox>
#include <Wt/WText>

using namespace Wt;

struct Event {
public:
    int choice;
    int number;
};

typedef boost::function<void (const Event&)> EventCallback;

class TestServer : boost::noncopyable {
public:

    class Client {
    };

    TestServer(Wt::WServer& server) : 
    _server(server),
    _choice(1),
    _number(7)
    {}

    bool connect(Client *client,
         const EventCallback& callback) {
    if (_clients.count(client) == 0) {

        ClientInfo info;
        info.session = WApplication::instance()->sessionId();
        info.callback = callback;
        _clients[client] = info;
        return true;
    } else {
        return false;
    }
    }

    void setChoice(int choice) {
    _choice = choice;
    updateAllSettings();
    }

    void setNumber(int number) {
    _number = number;
    updateAllSettings();
    }

private:

    struct ClientInfo {
    std::string session;
    EventCallback callback;
    };

    void updateAllSettings() {
    Event event;
    event.choice = _choice;
    event.number = _number;

    for (auto i=_clients.begin(); i!=_clients.end(); ++i) {
        _server.post(i->second.session,
             boost::bind(i->second.callback, event));
    }
    }

    int _choice;
    int _number;
    std::map<Client*, ClientInfo> _clients;
    Wt::WServer& _server;
};

class SettingsDialog : public Wt::WDialog {
public:
    SettingsDialog(TestServer& server)  :
    WDialog("Settings"),
    _server(server)  {


    _layout = new WGridLayout();
    _layout->setContentsMargins(2, 2, 2, 2);

    contents()->setLayout(_layout);

    _layout->addWidget(new Wt::WText("Choice: "),  0, 0);

    _choiceCombo = new Wt::WComboBox();

    _choiceCombo->addItem("Option Zero");
    _choiceCombo->addItem("Option One");

    _layout->addWidget(_choiceCombo, 0, 1);

    _layout->addWidget( new Wt::WText("Number: "), 1, 0);

    _numberSpinner = new Wt::WSpinBox();
    _numberSpinner->setRange(0,100);
    _numberSpinner->setSingleStep(5);
    _numberSpinner->setValue(25);
    _layout->addWidget(_numberSpinner, 1, 1);

    _choiceCombo->activated()
        .connect(this, &SettingsDialog::choiceChanged);

    _numberSpinner->valueChanged()
        .connect(this, &SettingsDialog::numberChanged);

    setPositionScheme(Fixed);
    setOffsets(5, Left);
    setOffsets(5, Top);
    setModal(0);
    show();
    }

    void setChoice(int choice) {
    _choiceCombo->setCurrentIndex(choice);
    }

    void setNumber(int n) {
    _numberSpinner->setValue(n);
    }

protected:

    void choiceChanged(int arg) { 
    _server.setChoice(arg); 
    }

    void numberChanged(int arg) { 
    _server.setNumber(arg);
    }

    Wt::WGridLayout* _layout;
    Wt::WComboBox* _choiceCombo;
    Wt::WSpinBox* _numberSpinner;

    TestServer& _server;
};


class TestApplication : public Wt::WApplication,
            public TestServer::Client {
public:

    TestApplication(const Wt::WEnvironment& env, 
            TestServer& server)
    : WApplication(env),
      _server(server)
    {
    messageResourceBundle().use(appRoot());

    _settingsDialog = new SettingsDialog(_server);

    Wt::WApplication::instance()->enableUpdates(true);

    _server.connect(this, boost::bind(&TestApplication::processEvent, this, _1));
    }

    virtual ~TestApplication() {}

    void processEvent(const Event& event) {
    _settingsDialog->setChoice(event.choice);
    _settingsDialog->setNumber(event.number);
    triggerUpdate();
    }

private:

    TestServer& _server;
    SettingsDialog* _settingsDialog;
};



WApplication *createApplication(const WEnvironment& env,
                TestServer& server) {
    return new TestApplication(env, server);
}



int main(int argc, char **argv)
{
    Wt::WServer server(argv[0]);
    TestServer testServer(server);

    server.setServerConfiguration(argc, argv, WTHTTP_CONFIGURATION);

    server.addEntryPoint(Wt::Application,
             boost::bind(createApplication, _1,
                     boost::ref(testServer)));

    if (server.start()) {
    int sig = Wt::WServer::waitForShutdown();
    std::cerr << "Shutting down: (signal = " << sig << ")" << std::endl;
    server.stop();
    }
}

RE: WCombo Box Mysteriously Grows Taller - Added by Koen Deforche over 11 years ago

Hey,

Thanks for the test-case. I haven't been able to reproduce the problem yet, on Windows 7 / Windows XP or MacOSX hosts, so I guess that the problem is specific to Windows Vista --- I'll try that too.

Regards,

koen

RE: WCombo Box Mysteriously Grows Taller - Added by Ben Jackson over 11 years ago

Thanks for taking the time to look at it, Koen. I am actually able to reproduce both the Chrome and Firefox behaviors on Windows 7. Maybe it's related to Wt 3.2.1?

Ben

RE: WCombo Box Mysteriously Grows Taller - Added by Koen Deforche over 11 years ago

Hey Ben,

Oops, I thought I had read that you also had the behaviour with 3.2.3 / git versions, but I must have been mixing two different reports.

I'ld guess that indeed it is a bug in 3.2.1 that has since been fixed (in 3.2.3).

Regards,

koen

    (1-7/7)