restore the toggle button status in ionic2 - ionic2

On ionChange I am checking some condition, if condtion is set to false I want to restore the toggle buttons previous position. Here is the relevant code
changeStatus(item) {
if(this.mqttservice.response) {
//doing smthg
}
else {
item.status =!item.status;
//bring back the toggle to previous position
}
}
<ion-toggle [(ngModel)]="item.status" (ionChange)="changeStatus(item);" checked="false">
The issue is since I am changing the state changeStatus() is called indefinitely. How do I prevent this and restore toggle button previous position on else condition?

The [()] syntax means you are getting updates and posting updates when the variable changes. Since you are using (ionChange) you can use the [] syntax instead, which means it only gets updates (but won't post them)
<ion-toggle [ngModel]="item.status" (ionChange)="changeStatus($event, item);">
Since the toggle button changes its state, in order for it to "change back" you need to toggle the value back and forth. You can solve this by setting the value and then if it fails, trigger a change "in the future" by adding a setTimeout.
public changeStatus(event: boolean, item: Item) {
item.status = event;
if (allGood) {
// do something
}
else {
// revert to old value
setTimeout(() => { item.status = !event; });
}
}

Related

Blocking signal one time in Qt doesn't work correctly

Hi i have following code:
void MainWindow::on_listWidgetNotes_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)//Test!
{
if(current != NULL)
{
ui->plainTextEditContent->setEnabled(true);
change = false;
if(isModified)
{
auto reply = QMessageBox::question(this, "Test", "Do you want save changes?", QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel);
if (reply == QMessageBox::Yes) on_pushButtonSave_clicked();
else if(reply == QMessageBox::No) notes.closeFile();
else
{
//ui->listWidgetNotes->blockSignals(true);
ui->listWidgetNotes->setCurrentItem(previous);
//ui->listWidgetNotes->blockSignals(false);
return;
}
}
isModified = false;
this->setWindowTitle(current->text()+" - VfNotes 1.0");
ui->plainTextEditContent->setPlainText(notes.openFile(current->text()));
}
}
In specified case code have to show message box and set focus on previous item, after select cancel button.
But setCurrentItem calls on_listWidgetNotes_currentItemChanged again with this message box. After use blockSignals focus doesn't come back on previous element. What to do to set focus on previous item after click cancel, that on_listWidgetNotes_currentItemChanged wasn't call again?
So, if this is the slot that gets called when the selection changes, then instead this slot getting called , create another slot and from there, you call this function..
Now this new slot will have the previous item and from there if the function returns a book instead of void signifying that a cancel is pressed, then you call setCurrentItem again...

CTabView how to prevent switching

I use CTabView thats hold different FormViews.
I can switch to another view without any problem.
From a ParamView I don't want to allow switch to another view until the changed value are confirmed.
I have tried it with OnActivateView(..), OnShowWindow(..). But they are too late, the view are already moved to a another view, then these handlers are fired. :(
void CParamView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
/* // did not work, next View already shown before
if (!bActivate && pActivateView != pDeactiveView)
{
if (ParamValueChanged())
{
if (!ConfirmChangedValues())
return;
}
}
*/
CFormView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}

How to disable next button in QWizard

What I'm trying to do
I am trying to create a subclass of QWizardPage that looks somewhat like this,but has a slight tweak. I want to disable the next button when a counter variable is more than 0. (It can't be 0 from the get-go due to some functionality that requires it to go x..x-1...0).
What I've tried
Reimplement isComplete() and emit completeChanged() in the constructor
bool DemoWizardPage::isComplete()
{
return ! (counter > 0); //Also tried just return false;
}
Reimplement initializePage and disable the next button from there
void DemoWizardPage::initializePage()
{
qDebug() << "QWizardPage:: initialize page";
if (!this->isComplete())
{
qDebug() << "try to turn off next button";
wizard()->button(QWizard::NextButton)->setDisabled(true);
qDebug() << "next button enabled? "
<< wizard()->button(QWizard::NextButton)->isEnabled();
}
}
Results so far
From stepping through the code I can see that the next button is disabled when the page loads. But then it is enabled again due to these 2 lines in QWizardPrivate (taken from qwizard.cpp)
bool complete = page && page->isComplete();
btn.next->setEnabled(canContinue && complete);
I am quite baffled as to why isComplete() is returning true here. I mean, I set my counter to be 2 at the beginning and I never decrease it. (And yes, I do emit a completeChanged() whenever I set the counter).
Any ideas?
QWizard automatically manages the state of Next button based on the QWizardPage::isComplete(), you should not implement that functionality yourself in initializePage(). The reason your isComplete() is not being called is that it doesn't actually overwrite QWizardPage::isComplete const from QWizardPage. Declare your function const and it will properly overwrite the original function.

qslider sliderReleased value

I m trying to make a media player . The time status of the track is shown using QSlider. Track seek should happen when the user releases the slider somewhere on the QSlider. I had a look on the list of QSlider signals. The one that seems to fit is sliderReleased() which happens when the user releases the slider, but it does not get the latest value of where slider is. So to get sliders latest value I used sliderMoved() and stored reference.
Signal and slot connection
connect(this->ui->songProgress, SIGNAL(sliderMoved(int)), this,
SLOT(searchSliderMoved(int)));
connect(this->ui->songProgress, SIGNAL(sliderReleased()), this,
SLOT(searchSliderReleased()));
Functions
void MainWindow::searchSliderMoved(int search_percent)
{
value=this->ui->songProgress->value();
std::cout<<"Moved: Slider value"<<value<<std::endl;
}
Now I am Using the "value" variable inside searchSliderReleased for seeking
void MainWindow::searchSliderReleased()
{
std::cout<<"Released: Slider value"<<value<<std::endl;
emit search(value);//seek the track to location value
}
But the problem with above technique is that sliderMoved signal does not give the value where the slider is dropped but it give the location from where the slider was moved. How do I obtain the value where the slider was dropped?
You can use the valueChanged(int) signal of the slider, but set the flag
ui->horizontalSlider->setTracking(false);
Just finished building a DiectShow media player with QSlider here at work. Here's a few slot snippets on how I did it.
Widget::sliderPressed()
{
if( isPlaying() )
{
m_wasPlaying = true;
pause();
}
else
{
m_wasPlaying = false;
}
// Set a flag to denote slider drag is starting.
m_isSliderPressed = true;
}
Widget::sliderReleased()
{
if( m_wasPlaying )
{
play();
}
m_wasPlaying = false;
m_isSliderPressed = false;
}
Widget::valueChanged( int value )
{
if( m_isSliderPressed )
{
// Do seeking code here
}
else
{
// Sometime Qt when the user clicks the slider
// (no drag, just a click) Qt will signals
// pressed, released, valueChanged.
// So lets handle that here.
}
}
Had the same problem and calling sliderPosition() instead of value() directly when handling sliderReleased() worked for me.
I prefer to save the last value set by our app, like this pseudocode:
// Save our last value
lastSoftwareVal = 0;
// Set value from program
slider_set_value(value){
lastSoftwareVal = value;
slider.setValue(value)
}
// Slider on change callback
slider_on_change(value){
if(value == lastSoftwareVal){
// Value was changed by our app
return false;
}
// User has changed the value, do something
}

Mac event tap just delays discarded events

I'm trying to write some code that discards all keyboard and mouse events when enabled on Mac OSX 10.6. My code runs as the root user. The approach I'm taking is to create an event tap that discards all events passed to it (while enabled). The event tap callback function looks like this:
CGEventRef MyTapCallback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void *refcon)
{
return CKeyLocker::isEnabled() ? NULL : event;
}
And the code I'm using to enable and disable the event tap looks like this:
void CKeyLocker::enable(bool bEnable)
{
if (bEnable == m_bEnabled)
return;
if (bEnable)
{
// which events are we interested in?
CGEventMask evMask = kCGEventMaskForAllEvents;
CFMachPortRef mp = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
evMask,
MyTapCallback,
NULL);
if (mp)
{
qDebug() << "Tap created and active. mp =" << mp;
m_enabledTap = mp;
m_bEnabled = true;
}
}
else
{
CGEventTapEnable(m_enabledTap, false);
CFRelease(m_enabledTap);
m_enabledTap =0;
m_bEnabled = false;
qDebug() << "Tap destroyed and inactive";
}
}
This approach works very well while the event tap is active - I can hammer on the keyboard and mouse as much as I want and no events make it through the system. However, when the tap is disabled all the keys I pushed while the tap was active appear in the current window. It's like the event tap is just delaying the events, rather than destroying them, which is odd, since the Mac documentation clearly states:
If the event tap is an active filter, your callback function should return one of the following:
The (possibly modified) event that is passed in. This event is passed back to the event system.
A newly-constructed event. After the new event has been passed back to the event system, the new event will be released along with the original event.
NULL if the event passed in is to be deleted.
I'm returning NULL, but the event doesn't seem to be deleted. Any ideas?
The linked comment does not have an answer from what I see, so I'll dump some info from what I've seen when poking around with this stuff.
First, I have much better luck with CGEventTapCreateForPSN. It's as if the system gives you some leeway for restricting your tap. However, from this example it looks like this is not sufficient.
Next up - and this /may/ be all you need... In your call back, you probably want (and may need) to check for the following events:
switch (type)
{
case kCGEventTapDisabledByTimeout:
case kCGEventTapDisabledByUserInput:
{
CFMachPortRef *pTap = (CFMachPortRef*)refcon;
CGEventTapEnable( *pTap, true );
return NULL;
}
default:
break;
}
Regardless of what the various documentation does or doesn't say, it's been my observation that the OS feels like it's 'probing' for bad callbacks; basically disabling event tap callbacks that are universally eating events. If you re-register in these cases the OS seems to be ok with it, as if saying: OK, you seem to know what you're doing, but I'll probably poke you again in a bit to make sure.
It's really strange, we use event taps for the same purpose (input blocking in a given scenario) and works perfectly 10.4 - 10.8.2. excpet one thing, it should not block or receive events from a password dialog (which is not a big surprise)
What I can see now is different compared to you sample is:
we use kCGTailAppendEventTap instead of kCGHeadInsertEventTap (this should not matter)
we do some event logging in the installed callback
we have some user event data in some self injected events, that filtered out, but apart from this we simply return NULL to drop an unwanted event (like you do), I can confirm, not all events are ignorable!
we turn on/off the event tap this way:
bool SetInputFilter(bool bOn)
{
bool result = false;
CFRunLoopRef runLoopRef = CFRunLoopGetMain();
if (bOn) {
// Create an event tap.
CGEventMask eventMask = kCGEventMaskForAllEvents;
if ((m_eventTapInput = CGEventTapCreate(kCGHIDEventTap,
kCGTailAppendEventTap,
kCGEventTapOptionDefault,
eventMask, CGInputEventCallback, this)) == NULL) {
Log(L"Failed to create event tap");
return result;
}
// Create a run loop source.
m_runLoopEventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapInput, 0);
CFRelease(m_eventTapInput); // CFMachPortCreateRunLoopSource retains m_eventTapInput
if (m_runLoopEventTapSource == NULL) {
Log(L"Failed to create run loop source for event tap");
return result;
}
// Add to the current run loop.
CFRunLoopAddSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode);
CFRelease(m_runLoopEventTapSource); // CFRunLoopAddSource retains m_runLoopEventTapSource
result = true;
}
else {
// Disable the event tap.
if (m_eventTapInput)
CGEventTapEnable(m_eventTapInput, false);
// Remove our run loop source from the current run loop.
if (runLoopRef && m_runLoopEventTapSource) {
CFRunLoopRemoveSource(runLoopRef, m_runLoopEventTapSource, kCFRunLoopCommonModes);//kCFRunLoopDefaultMode);
m_runLoopEventTapSource = NULL; // removing m_runLoopEventTapSource releases last reference of m_runLoopEventTapSource too
m_eventTapInput = NULL; // removing m_runLoopEventTapSource releases last reference of m_eventTapInput too
}
}
return result;
}
I can verify that returning NULL does effectively delete some events, but i have also seen times when it does not, exactly how it decides what deletions to permit is unclear but it looks like mass deletions seem to be prevented e.g.: when you delete more than 100 events or so in a row.