Project

General

Profile

Actions

Feature #7030

closed

WinPlaceEdit Signal Lacks Source Identification

Added by John Robertson almost 5 years ago. Updated almost 5 years ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
05/02/2019
Due date:
% Done:

0%

Estimated time:

Description

I cannot find a Signal produced by WInPlaceEdit which provides identification of the object from which the Signal originates. This makes it very cumbersome to use for an application where the instances of WInPlaceEdit are not known at compile time.

I would expect an API something like this:

WInPlaceEdit::addData(void *data);
void* WInPlaceEdit::data();

Signal<WInPlaceEdit*>& valueChanged();
Actions #1

Updated by Roel Standaert almost 5 years ago

All of the signals in Wt are like that, the idea being that any necessary context information can be passed into the callback function using either lambda capture or bind expressions. I don't think we can just change Signals everywhere in Wt.

Actions #2

Updated by John Robertson almost 5 years ago

You realize that the most likely context information any programmer needs to know is a pointer to the object which generated the signal, right? I realize that WInPlaceEdit could easily be wrapped in a class that does exactly what I suggested, or you can do lambda capture or bind, but that is extra work for essentially what should have been handed to me in the first place.

Actions #3

Updated by Wim Dumon almost 5 years ago

Hey John,

In Wt 3 we offered WObject::sender() as a means to extract the sender of a signal. We dropped this in Wt 4, since C offers much more powerful means to provide context information in signal connections than the WObject pointer returned by the sender() call, which needs to be dynamic_casted to obtain actionable information. Class WSignalMapper, which was a framework to work around the annoyances of WObject::sender(), was also dropped.

https://webtoolkit.eu/wt/wt3/doc/reference/html/classWt_1_1WObject.html#a413deb54de40ee278dd554e4960d58ca

For example, in the hangman example, we used to use WObject::sender() in combination with WSignalMapper to obtain information in the processButton about which one of the 26 character buttons was pressed. Using bind or lambda constructs, this contextual information can be passed in a single line in a typesafe way:

    WPushButton *character = ...;
    character->clicked().connect
      (std::bind(&LettersWidget::processButton, this, character));

You can freely choose which contextual information is best appropriate to your application - be it the WPushButton from which the signal originates (as in this example), or maybe the character it represents, or maybe still something else (a datastructure related thereto?). I've learned that this typically leads to less work for the programmer, and as an added bonus everything is fully typechecked - no dynamic_casts.

To map this back to your example:

  {
    MyDataStructure *data = ...; // no need for void *
    WInplaceEdit *editor = ...;
    editor->valueChanged().connect
      (std::bind(&MyWidget::handleNewValue, this, data));
  }
  void MyWidget::handleNewData(MyDataStructure *data) {
     ...;
  }

Best regards,

Wim.

Actions #4

Updated by John Robertson almost 5 years ago

Thank you Wim for the helpful example. This is what I was hoping for :-)

Actions #5

Updated by John Robertson almost 5 years ago

Don't mean to be quarrelsome, but std::bind & lambda capture are not a comprehensive replacement for an untyped data pointer. Providing an untyped data pointer facility supports assignment of context at any time during an object's lifespan, where std::bind & lambda capture are useful only if the context is known at the time connect() is called. Again, your classes can alway be wrapped, but why not make them as useful as possible as they are?

Consider the following, which requires none of the mentioned c shenanigans, and supports context assignment at any time:

class WInPlaceEdit {
...
   Signal<WInPlaceEdit*> valueChanged_;
...

   void valueChanged() {
      valueChanged_.emit(this);
   }
};

class ProgrammerClass {
...
   void someInPlaceEditChanged(WInPlaceEdit *ipe) {
      WString newValue= ipe->text();
      void *ctxtAssignedAtAnyTime= ipe->data();
      // Do stuff with ipe, newValue, ctxtAssignedAtAnyTime
   }
};
Actions #6

Updated by Wim Dumon almost 5 years ago

Hey John,

I notice two different requests in your question:

  • I want to identify the sender of a signal
  • I want to associate my own data to any class

For the first point, see my first reply.

For the second point, I believe it's not general practice that C libraries have facilities for this in their API (can you refer to an example?). There are other ways to achieve this, such as extending WInplaceEdit by inheritance, keep an std::map<> in ProgrammerClass to associate data with observing pointers, binding an extra shared_ptr<> which contains contextual data object, ...

BR,

Wim.

Actions #7

Updated by John Robertson almost 5 years ago

Wim,

I'm a paying Wt customer asking for features which will make Wt easier for me to use. You have supplied examples (std::bind(), lambda capture) which will work for my case, but not all cases. If you do not find compelling the utility of my proposal, then further discussion is pointless.

Feel free to mark this closed.

Actions #8

Updated by John Robertson almost 5 years ago

In case anyone is interested, here is a WInPlaceEdit wrapper class which does exactly what I proposed:

using namespace Wt; 

class InPlaceEdit : public WInPlaceEdit {
public:

   InPlaceEdit() : WInPlaceEdit(), _data(NULL) {
      this->valueChanged().connect(this, &InPlaceEdit::valueChangedProxy);
   }   

   ~InPlaceEdit() {}

   Wt::Signal<InPlaceEdit*>& changed() {
      return _changed;
   }   

   void setData(void *data) {
      _data= data;
   }   

   void *data() {
      return _data;
   }   

private:
   void valueChangedProxy(WString) {
      _changed.emit(this);
   }   

   Wt::Signal<InPlaceEdit*> _changed;
   void *_data;
};
Actions #9

Updated by Roel Standaert almost 5 years ago

  • Status changed from New to Rejected
Actions

Also available in: Atom PDF