I'm working with a custom List component in flex4. I've created a custom ItemRenderer and everything looks and works as i want, but i'm trying to get the double click event. I'm receiving key down and all other events, but not this one. I've enabled the double click on the List component
doubleClickEnabled="true"
and i've added an event listener for
ListEvent.ITEM_DOUBLE_CLICK
I can click as long as i want, the event just is not triggered.
I could use any advice.
Thanks.
You want to listen for MouseEvent.DOUBLE_CLICK and then you can figure out what was clicked on using event.target.
I banged my head on the wall for hours because of this ! Adobe is going backwards with component functionality ! anyway, I found a decent solution :
We're going to add the DOUBLE_CLICK event listener to the dataGroup of the list, which is the container of the items :
list.dataGroup.doubleClickEnabled = true;
list.dataGroup.addEventListener(MouseEvent.DOUBLE_CLICK, handleDoubleClick);
Now it works nice, not provoking a double click from the scroller, but sill provoking a double click from an open space (the dataGroup itself) in the list where there are no items. so we only continue the event handler if e.target != dataGroup :
private function handleDoubleClick(e:MouseEvent):void
{
if (list.dataGroup != e.target)
{
// double click code
}
}
Now it works fine :) phew ! We shouldn't waste time on this stuff...
Bad solution --> DO NOT try to compare e.target's class to the itemRenderer's class of the list, since sometimes e.target is the actual label of the item.
Related
I'm creating my first C++ wxWidgets application. I'm trying to create some kind of split button where the options are displayed in a grid. I have a custom button class which, when right-clicked on, opens a custom wxPopupTransientWindow that contains other buttons.
When I click on the buttons in the popup, I want to simulate a left click on the main button. I'm trying to achieve this through events, but I'm kinda confused.
void expandButton::mouseReleased(wxMouseEvent& evt)
{
if (pressed) {
pressed = false;
paintNow();
wxWindow* mBtn = this->GetGrandParent();
mBtn->SetLabel(this->GetLabel());
mBtn->Refresh();
wxCommandEvent event(wxEVT_BUTTON);
event.SetId(GetId());
event.SetEventObject(mBtn);
mBtn-> //make it process the event somehow?
wxPopupTransientWindow* popup = wxDynamicCast(this->GetParent(), wxPopupTransientWindow);
popup->Dismiss();
}
}
What is the best way to do this?
You should do mBtn->ProcessWindowEvent() which is a shorter synonym for mBtn->GetEventHandler()->ProcessEvent() already mentioned in the comments.
Note that, generally speaking, you're not supposed to create wxEVT_BUTTON events from your own code. In this particular case and with current (and all past) version(s) of wxWidgets it will work, but a cleaner, and guaranteed to also work with the future versions, solution would be define your own custom event and generate it instead.
Problem: can't trigger Vue-Select3 item dropdown selection programmatically in unit-tests.
I have tried with both vue-test-utils and #testing-library/vue as well as triggering a click event programmatically in a browser to force list item selection. However, none of these worked. The only way I managed to trigger selection is by getting a VueSelect instance and emitting 'input' event. I also tried to trigger different events on dropdown container, etc.
// Failed
// testing-library
const dropdownItem = getAllByTestId('dropdown-item')
fireEvent.click(dropdownItem[0])
// test-utils
wrapper.find('[data-testid=dropdown-item]').trigger('click')
// In browser
document.querySelectorAll('.vs__dropdown-item')[0].click()
// Success
wrapper.find(VueSelect).vm.$emit('input', payload)
Current result: When a click event is triggered nothing happens.
Expected result: When a click event is triggered Vue-Select should select the item and emit 'input' event.
I found a way of selecting an option directly. You can use the select function of the VueSelect component, like that:
const wrapper = mount(YourComponent)
const vueSelect = wrapper.find(VueSelect)
vueSelect.vm.select(yourOptionToSelect)
That will work if you just want to select a specific option.
But yes, if you want to simulate the click on one of the options, that would not be helpful. And I know that this way of changing the state of a component is not the preferred way of doing this, but it is the only solution I've found.
Let's say that I have a group of radio items in a wxMenu. I know that exactly one of these will be checked at any given time.
Does the wxMenu or some other construct hold onto the index of the checked item, or do I need to call the isChecked on each radio item till I find the checked element to find it's index?
I've asked this question about how to do that, but I'd much prefer wxWidgets saved me from doing that everywhere.
No, saving the index of the last selected item (as shown in ravenspoint's answer) or using wxMenuBarBase::IsChecked() until you find the selected radio button is the only way to do it.
For wxWidgets to provide access to the currently selected button it would need not only to store it (which means not forgetting to update not only when the selected changes, but also when items are inserted into/deleted from the menu, so it's already not completely trivial), but to somehow provide access to the radio items group you're interested in, which would require being able to identify it and currently there is no way to do it and adding it isn't going to be particularly simple.
What could be done easily, however, is writing a reusable function int GetIndexOfSelectedRadioItem(int firstItem) that would start at the given item and call IsChecked() on subsequent items until it returns true and return the offset of the item. You should be able to do it in your own code, but if you'd like to include such function in wxWidgets itself (as a static wxMenuBar method, probably), please don't hesitate to send patches/pull requests doing it!
It is easy enough to roll your own.
Bind an event handler to wxEVT_COMMAND_RADIOBUTTON_SELECTED for every button. In the handler, extract the ID of the selected radio button and store it somewhere.
Like this:
ResolMenu = new wxMenu();
ResolMenu->AppendRadioItem(idRcvLoRez,"Low Resolution");
ResolMenu->AppendRadioItem(idRcvMeRez,"Medium Resolution");
ResolMenu->AppendRadioItem(idRcvHiRez,"High Resolution");
ResolMenu->Check( idRcvLoRez, true );
Bind(wxEVT_MENU,&cFrame::onRcvRez,this,idRcvLoRez);
Bind(wxEVT_MENU,&cFrame::onRcvRez,this,idRcvMeRez);
Bind(wxEVT_MENU,&cFrame::onRcvRez,this,idRcvHiRez);
void onRcvRez( wxCommandEvent& event )
{
myRezID = event.GetId();
I've run into a bit of an issue related to a whitelist Web Browser my company has been developing / maintaining for one of our product lines. The browser runs on top of Qt 4.8.6, using qtwebkit (Migration to 5.X would be ideal, but the embedded Linux OS we're using is too old to support the newer versions based on our testing, and upgrading to a newer OS is too costly to us / our customers). The primary interface to the browser is a 6x8 touchscreen, mounted inside an aircraft cockpit.
For sites that have things like scrollable/embedded maps (ex. Google Maps), the users of the browser want the ability to drag the entire page when they are selecting something outside of the map, and drag just the map (without the entire page scrolling) when the map is selected (Ala most of the popular mobile browsers).
Thus far, I am able to do one or the other, but not both:
When I hook mouse handlers into a QWebView or QGraphicsWebView, I can turn the cursor into a hand and very easily support dragging of the entire web page. However, that inhibits the page's ability to handle the mouse events for when a user is pulling over a map (i.e. When a user drags over a map, it drags the entire page without moving the map).
When I don't add in the hooks to handle mouse events, things like maps are scrollable by grapping/dragging them, but of course the user loses the ability to drag the entire page.
Right now, the browser uses the later, with scroll bars disabled and a directional-arrow overlay to allow the user to scroll the entire page (as the display size is limited, and scrollbars take up too much space when they are sized large enough for the user to interact with them)...but this is not ideal.
My Question: Is there any easy way to make it so that the page, and elements in a page, can be scrolled seamlessly?
Thanks!
Rob
Seems to me like you need to check if you are over such a map and ignore(pass along) the event in that case. I think you should be able to do something like this:
bool GraphicsWebView::isOverMap(QPoint pos) {
QWebPage* webPage = this->page();
if (webPage) {
QWebFrame* webFrame = webPage->frameAt(pos);
if (webFrame) {
QString selectorQuery = "#map-canvas"; // Based on https://developers.google.com/maps/tutorials/fundamentals/adding-a-google-map
QList<QWebElement> list = webFrame->findAllElements(selectorQuery).toList(); // Find all the maps!
foreach(QWebElement element, list) {
if (element.geometry().contains(pos)) {
return true; // Cursor is over a map
}
}
}
}
return false; // No match
}
Obviously this is a pretty specific function but there is probably a way to come up with a better selector query that will apply to all those kinds of QWebElement.
Assuming you hook mouse events by subclassing QGraphicsWebView and reimplementing void mouseMoveEvent(QGraphicsSceneMouseEvent * event), I suggest you do something like:
void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
if (isOverMap(mapFromScene(event->scenePos()).toPoint())) { // We got a map!
event.ignore(); // Clear the accept flag
return; // Return, we're done here
}
handleMoveView(); // Not over any maps, let's scroll the page
}
This part of the doc explains how events are handled with regard to the topmost item. I especially recommend you read the third paragraph.
Hope that helps!
EDIT: Did a bit more research and it looks like something like that could be more generic:
graphicsView.focusItem()->flags().testFlag(QGraphicsItem::ItemIsMovable);
It's at the very least worth investigating as a replacement to isOverMap()
EDIT: Gotcha, here is something you can try then.
Start by subclassing QGraphicsSceneMouseEvent and add a signal called void destroyedWithoutAccept() that's emitted in the destructor if the event has not been accepted.
Then modify mouseMoveEvent to look like this:
void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
MyEvent myEvent = new MyEvent(event); // Copy event
event.accept(); // accept original event
connect(myEvent, SIGNAL(destroyedWithoutAccept),
this, SLOT(handleMoveView)); // Callback if unused
QGraphicsWebView::mouseMoveEvent(myEvent); // Pass it to Base class
}
If that works, it might introduce a bit of delay if deleteLater is used to destroy it. But in that case reimplement it as well.
Want to trigger function on mouse click in browser window via C++ plugin, written with FireBreath.
But with code below nothing happends on click.
Got the following code in TestPluginAPI.h:
BEGIN_PLUGIN_EVENT_MAP()
EVENTTYPE_CASE(FB::MouseDownEvent, onMouseDown, FB::PluginWindow)
END_PLUGIN_EVENT_MAP()
virtual bool onMouseDown(FB::MouseDownEvent *evt, FB::PluginWindow *);
And this code in testPluginAPI.cpp:
bool TestPluginAPI::onMouseDown(FB::MouseDownEvent *evt, FB::PluginWindow *)
{
if(evt->m_Btn == FB::MouseButtonEvent::MouseButton_Left)
{
fire_showcrd(FB::variant_list_of(evt->m_x)(evt->m_y));
}
return 0;
}
Fire_showcrd(...) was tested separately and it's working. It seems that something wrong with click detecter part, but what?
The PluginWindow events in FireBreath only apply to the region where the plugin lives, not elsewhere on the webpage. You'll only get events when the plugin itself is clicked on using this method, and if any DOM elements are hovering over your plugin (even if your plugin draws in front because it's windowed) you may end up losing the events to that element.
You can get click events for the whole page by using javascript.