It's hard to explain my problem so give me a break if it's not very clear.
I have some ten properties that can be edited in the view. Most of them are booleans. These properties configure a test environment (like one property can be configured to show the solution).
Now, the problem is that some properties can't be set to true if others are set to false. Nothing would go wrong, but it's just useless. It's like one property would be configured not to show the correct button and another to show the solution. In our system, if you can't click on the correct button, then solution will never be shown.
Does this kind of problem have a name?
Do such properties have a name (just like there are immutable properties)?
Are there best-practices to implement such a story? We can hard code it in the view, but I would rather have a generic system.
The word you're looking for is orthogonality. The settings are not orthogonal, as they can't vary independently.
As to how to handle showing these properties, the completely generic way to do it (and your problem may not warrant the coding cost of this genericicity) would be to give each control an expression that references the other controls, where if the complete expression evaluates to true (or false), the control is disabled in the view.
Easier to code would be a control that exposed an isDisabled() method, which you could override as necessary. Here's a short Java example, which leverages Java anonymous classes to do the hard work. It assumes there's already a Control class, with a booleanValue() getter that converts it to a boolean, and that since AutoDisabledControl is-a Control, it can be used as a drop-in replacement for a Control:
public class AutoDisabledControl extends Control {
public isDisabled() { return false ; }
}
..... usage ....
// control1 is never disabled
final Control1 = new AutoDisabledControl() ;
// Control2 is disabled if control1 is false
final Control2 = new AutoDisabledControl() {
public isDisabled() { return control1.booleanValue() == false; }
};
// conntrol 3 is enabled only if control1 and control2 are true
final Control1 = new AutoDisabledControl() {
public isDisabled() { return ! (
control1.booleanValue()
&& control2.booleanValue()) ;
};
Naturally, in the View's display, it checks each control's isDisabled() , and disables the ones that return true; when a Control's value is changed, the view redisplays. I'm assuming some sort of MVC Pattern.
You propably mismodeled your solution.
Try to think in a different way - perhaps U can eliminate some parameters that can be inferred from the others or u can use enumarations to combine few parameters into one.
Investigate your parameters' value space to find it out.
You could use an int or long to store the related properties and use a bit mask when setting a property to correctly clear invalid settings. This int or long could be in the form of a flagged enumeration.
[Flags]private enum BitValues
{
Bit1 = 1 << 0, //Inclusive
Bit2 = 1 << 1, //Exclusive to bit 3 and 4
Bit3 = 1 << 2, //Exclusive to bit 2 and 4
Bit4 = 1 << 3, //Exclusive to bit 2 and 3
ExclusiveBits = Bit2 | Bit3 | Bit4 //All exclusive bits
}
private BitValues enValues;
public bool Bit1
{
get { return (enValues & BitValues.Bit1) == BitValues.Bit1; }
set
{
//Clear the bit
enValues = (enValues ^ BitValues.Bit1) & enValues;
//Set the bit
enValues = enValues | BitValues.Bit1;
}
}
public bool Bit2
{
get { return (enValues & BitValues.Bit2) == BitValues.Bit2; }
set
{
//Clear exclusive bits
enValues = (enValues ^ BitValues.ExclusiveBits) & enValues;
//Set bit
enValues = enValues | BitValues.Bit2;
}
}
Related
Preface
I have a simple app with a viewmodel, a custom UI control, and a TextView. Databinding is setup like this:
LiveData -> control.value -> control.preValue -> TextView
When LiveData is changed, databinding notifies control.value of the new value. control.value setter has a line which also gives the new value to control.preValue. Both properties have calls to their respective databinding listeners to notify databinding that the values have changed and that the UI should be updated. The text value of TextView is bound to control.preValue, so when the listener is notified, the TextView is updated.
This works well at runtime, however there is a problem at initialization.
The Problem
When the UI is first constructed, the LiveData value is not correctly propagated to the TextView. This is because the listeners have not yet been created by the android databinding library, so when control.preValue is set by control.value's setter, the listener is still null.
Diving deeper into executeBindings we can see the cause of the problem.
executeBindings is a function which is part of the *BindingImpl file automatically generated by the databinding library based on the Binding Adapters I have defined. It is responsible for initializing databinding, e.g. creating listeners, registering livedatas, and setting initial values to the UI.
executeBindings starts like this. It initializes variables for all the databound values.
#Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized(this) {
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
java.lang.Integer viewmodelBpmGetValue = null;
androidx.lifecycle.MutableLiveData<java.lang.Integer> viewmodelBpm = null;
int bpmPickerPreValue = 0;
androidx.lifecycle.MutableLiveData<java.lang.Boolean> viewmodelPlaying = null;
java.lang.String integerToStringBpmPickerPreValue = null;
int androidxDatabindingViewDataBindingSafeUnboxViewmodelBpmGetValue = 0;
com.okos.metronome.MetViewModel viewmodel = mViewmodel;
Next, it gets the value of control.preValue property and stores it in the earlier created variable. This is already the core of the problem. At this point control.preValue is still at the default value that is defined in the control's definition class, not the LiveData value which will be assigned to it a bit later.
if ((dirtyFlags & 0x18L) != 0) {
// read bpmPicker.preValue
bpmPickerPreValue = bpmPicker.getPreValue();
// read Integer.toString(bpmPicker.preValue)
integerToStringBpmPickerPreValue = java.lang.Integer.toString(bpmPickerPreValue);
}
Next we get the LiveData value from the viewmodel and register it with databinding
if ((dirtyFlags & 0x15L) != 0) {
if (viewmodel != null) {
// read viewmodel.bpm
viewmodelBpm = viewmodel.getBpm();
}
updateLiveDataRegistration(0, viewmodelBpm);
if (viewmodelBpm != null) {
// read viewmodel.bpm.getValue()
viewmodelBpmGetValue = viewmodelBpm.getValue();
}
// read androidx.databinding.ViewDataBinding.safeUnbox(viewmodel.bpm.getValue())
androidxDatabindingViewDataBindingSafeUnboxViewmodelBpmGetValue = androidx.databinding.ViewDataBinding.safeUnbox(viewmodelBpmGetValue);
}
Here it sets control.value to the value of the LiveData in the first if block. This line will trigger the control.value setter, which will set control.preValue, and those setters will both try to call their respective onChange listeners but they will be null because executeBindings hasn't created them yet. They are created in the 2nd if block.
if ((dirtyFlags & 0x15L) != 0) {
// api target 1
this.bpmPicker.setValue(androidxDatabindingViewDataBindingSafeUnboxViewmodelBpmGetValue);
}
if ((dirtyFlags & 0x10L) != 0) {
// api target 1
com.okos.metronome.view.DialPickerBindingAdapter.setPreValueListener(this.bpmPicker, (com.okos.metronome.view.PrePickerBase.OnValueChangeListener)null, bpmPickerpreValueAttrChanged);
com.okos.metronome.view.DialPickerBindingAdapter.setValueListener(this.bpmPicker, (com.okos.metronome.view.PrePickerBase.OnValueChangeListener)null, bpmPickervalueAttrChanged);
}
Finally, the value of the TextView is set, but it is set to the original value of preValue which we cached in a variable in the very first if block. **Not the new value which has been updated to preValue from the LiveData since then.
if ((dirtyFlags & 0x18L) != 0) {
// api target 1
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.tvBpmDisplay, integerToStringBpmPickerPreValue);
}
This seems like an oversight in the databinding library, and I wonder if anyone has any ideas of getting around this? The fix seems pretty simple to just move the first if block in executeBindings down so integerToStringBpmPickerPreValue is set after the value has been set from LiveData, but because executeBindings is automatically generated, I can't do that. There are some ways of changing the order of execution in executeBindings, like which order the bindings are defined in the xaml, but none of that affects the parts I want to change.
I have these three implementations, that (should) do essentially the same: return the current position of Android exoplayer or 0 as integer.
But only nr. 1 works. Nr. 2 and nr.3 always return 0, even though player is instantiated. Is that expected behaviour?
1.
private var playbackPosition = 0
get() {
return if (player == null) 0 else player?.currentPosition?.toInt() as Int / 1000
}
2.
private var playbackPosition = if (player == null) 0 else player?.currentPosition?.toInt() as Int / 1000
3.
private var playbackPosition = when(player) {
null -> 0
else -> player?.currentPosition?.toInt() as Int / 1000
}
Number 1 are an implementation of a get function and invoked every time you access the variable.
Number 2 and 3 initialize a variable and the right side are only invoked once at creation time of the variable. Means the playback position is calculated only once.
The behavior works like designed. If you need the new position every time you access the variable you have to use an own getter function.
Because of the question, I assume you're not that familiar with Kotlin and/or Java, so I'm going to explain the difference between the two.
First of all, you need to understand the difference between a function and a variable/constant. A function can have a varying result when it's called (assuming it's not a void/Unit), but a variable has a fixed result until it's updated. Take this:
var toggle = Random().nextBoolean()
var dependent = if(toggle) 0 else 1
toggle = !toggle
If you print the variable before and after the toggle is switched, the variable will not change. When it's been assigned, it stays with that value until something updates it. So if you add print statements, it will be the same. Let's expand on that:
var toggle: Boolean = Random().nextBoolean()
fun someFunction() : Int = (if(toggle) 0 else 1).also { toggle = !toggle }
The also block here is an extension function that lets you do stuff, but still return the variable it's called on. Here, either 1 or 0 is returned, and the toggle is inverted. If you call this two times, you'll see a different result. This is because you get a different value based on a condition. Again, you see the value doesn't change even though the toggle does.
TL;DR: Variables have a given value until changed. Methods returning values can change based on conditions, because it's updated every time it's called.
Now, what does this mean for your code?
First of all, for the first snippet, you should use val instead. Kotlin is really nice like that; if you override the getter of a val, you don't need to initialize it. It's called backing fields.
Anyways, this:
private val playbackPosition
get() {
return if (player == null) 0 else player?.currentPosition?.toInt() as Int / 1000
}
returns a value depending on the player variable when it is called. Where as the other examples:
private var playbackPosition = if (player == null) 0 else player?.currentPosition?.toInt() as Int / 1000
private var playbackPosition = when(player) {
null -> 0
else -> player?.currentPosition?.toInt() as Int / 1000
}
Set the value when they're defined. You could change those to a val too; they aren't automatically re-assigned.
Initial assignment, that being the code you have there, is only run once, and that's when the class is initialized. If the variable is inside a method, the variable is initialized when the method is called. lateinit vars can be set at a later time, but initial assignment is only run once. For any changes you'll need to update it.
However, this is where methods come in handy. Depending on what you have, you could also create a backing field, a "cache" in a way. This isn't necessary unless object creation is heavy. You don't need to worry about this for something as simple as integers. Using a method that returns the value (in your case, the getter), is kinda like doing this:
var x: Int = updateValue()
fun updateValue() : Int = if ... // alternatively does x = instead of returning an int
...
x = updateValue()
x.let { foo bar }
Although that is a considerably harder way of doing stuff.
But only Nr. 1 works. Nr. 2 and Nr.3 always return 0, although player is instantiated.
If you get 0 all the time for 2 and 3, that means player == null when the variables were intiailized, but it wasn't null when the getter for the first example was called.
Is that expected behaivour?
Considering the code, yes. It's by design.
TL;DR: Again, variables aren't automatically updated when a creating condition (i.e. player == null) changes. You'll either need to manually update it, or use methods over variables.
I'm using Windows Vista and Visual Studio 2010. Create a .Net 4 Windows Forms Application. Drop a progress bar on the default form, add code to handle the form load event and do a progressBar1.Value = 100; there.
Start debugging and you see an animation moving the progress bar to 100 in about half a second.
I need 2 progress bars in my project. One is for "global progress" and the second is for "current step progress" so the second goes from 0 to 100 and hen back to 0 for the next step. The problem is that with the progress bar being slow for some of the quick steps it never reaches 100 and it looks weird.
Is there a way to get rid of that animation? In WPF it's OK but I'd rather stay with Windows Forms.
This is just how the Vista/7 progress bar is designed. When you change the value of the progress bar, the bar is animated to that value progressively.
The only way I know of avoiding this problem is to go backwards when updating the progress bar, as follows:
progressBar1.Value = n;
if (n>0)
progressBar1.Value = n-1;
For a more complete discussion see Disabling .NET progressbar animation when changing value?
Building off of Heffernan's tip on going backwards with the progress bar and Reinhart's extension method approach in a related question, I came up with my own solution.
The solution is pretty seamless and successfully handles the issue you will encounter when the value is at Maximum. This extension method to ProgressBar alleviates the lagging that is caused from the progressive animation style present in the WinForms ProgressBar control when running on Windows Vista and 7 (I haven't tested on Windows 8 yet).
public static class ExtensionMethods
{
/// <summary>
/// Sets the progress bar value, without using 'Windows Aero' animation.
/// This is to work around a known WinForms issue where the progress bar
/// is slow to update.
/// </summary>
public static void SetProgressNoAnimation(this ProgressBar pb, int value)
{
// To get around the progressive animation, we need to move the
// progress bar backwards.
if (value == pb.Maximum)
{
// Special case as value can't be set greater than Maximum.
pb.Maximum = value + 1; // Temporarily Increase Maximum
pb.Value = value + 1; // Move past
pb.Maximum = value; // Reset maximum
}
else
{
pb.Value = value + 1; // Move past
}
pb.Value = value; // Move to correct value
}
}
Sample usage:
private void backgroundWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar.SetProgressNoAnimation(e.ProgressPercentage);
}
You can easily write a custom progress bar to show its value without animation. The following is a simple implementation to show the progress from 0 to 100 and revert to 0.
public class ProgressBarDirectRender : UserControl
{
private int _value;
public int Value
{
get { return _value; }
set
{
if (value < 0 || value > 100)
throw new ArgumentOutOfRangeException("value");
_value = value;
const int margin = 1;
using (var g = CreateGraphics())
{
if (_value == 0)
ProgressBarRenderer.DrawHorizontalBar(g, ClientRectangle);
else
{
var rectangle = new Rectangle(ClientRectangle.X + margin,
ClientRectangle.Y + margin,
ClientRectangle.Width * _value / 100 - margin * 2,
ClientRectangle.Height - margin * 2);
ProgressBarRenderer.DrawHorizontalChunks(g, rectangle);
}
}
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, ClientRectangle);
}
}
A much simpler answer, as shown here, is to do this:
pbar.Value = value;
pbar.Value = value - 1;
pbar.Value = value;
Explanation:
It animates the PB as it increases, but not while it decreases. And that is why the above hack sppears to 'fix' the problem.
I liked Derek W's answer and I managed to find a solution which supports data binding. I inherited from System.Windows.Forms.ProgressBar and created new bindable property. Otherwise it's the same:
[DefaultBindingProperty("ValueNoAnimation")]
public class NoAnimationProgressBar : ProgressBar
{
/// <summary>
/// Sets the progress bar value, without using 'Windows Aero' animation.
/// This is to work around (hack) for a known WinForms issue where the progress bar
/// is slow to update.
/// </summary>
public int ValueNoAnimation
{
get => Value;
set
{
// To get around the progressive animation, we need to move the
// progress bar backwards.
if (value != Maximum)
Value = value + 1; // Move past
else
{
// Special case as value can't be set greater than Maximum.
Maximum = value + 1;
Value = value + 1;
Maximum = value;
}
Value = value; // Move to correct value
}
}
}
You can bind to the property like this (viewModel has an int property called Value):
var dataSource = new BindingSource { DataSource = _viewModel };
progressBarBindingHack.DataBindings.Add("ValueNoAnimation", dataSource, "Value");
Within qt's item/view framework, I'm trying to save a QColorDialog as user data and then retrieve that dialog as the editor, as well as during paint, in a tableview.
In my class constructor I do
QStandardItem *item = new QStandardItem();
QColorDialog *colorDlg = new QColorDialog(QColor(0,0,255), this);
item->setData(QVariant::fromValue(colorDlg), ColorDialogRole);
mTableModel->setItem(0,2,item);
then, inside my delegate's paint function I have
void ReportFigureTableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QVariant vColorDlg= index.data(ReportFigure::ColorDialogRole);
if(vColorDlg.isValid())
{
////////////////////////////////////////////////
// Program segfaults on the next line ... why?
////////////////////////////////////////////////
QColorDialog *colorDlg = qvariant_cast<QColorDialog*>(vColorDlg);
if(colorDlg != NULL)
{
painter->save();
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
painter->fillRect(opt.rect, colorDlg->selectedColor());
painter->restore();
}
else
QStyledItemDelegate::paint(painter, option, index);
}
else
QStyledItemDelegate::paint(painter, option, index);
}
During runtime, the table shows up the first time (although with the wrong color ... different issue I assume). I double click to edit the cell and it brings up the dialog as expected. When I close, though, it segfaults on the indicated line. I don't understand why since I think I'm doing all the necessary checks.
You set the data on a QStandardItem object. Meanwhile you are retrieving the data on a QModelIndex object. Now why is the variant valid is a mystery. Maybe because ReportFigure::ColorDialogRole is equal to a build-in Qt role while it should be at least Qt::UserRole.
Anyway In the paint() method you can access the previously set item using
QStandardItem *item = mTableModel->itemFromIndex(index);
In my title screen, i have a code saying that the first controller using A is the PlayerIndex.one.
Here is the code:
public override void HandleInput(InputState input)
{
for (int anyPlayer = 0; anyPlayer <4; anyPlayer++)
{
if (GamePad.GetState((PlayerIndex)anyPlayer).Buttons.A == ButtonState.Pressed)
{
FirstPlayer = (PlayerIndex)anyPlayer;
this.ExitScreen();
AddScreen(new Background());
}
}
}
My question is: How can i use the "FirstPlayer" in other classes? (without this, there is no interest in this code)
I tried the Get Set thing but i can't make it work. Does i need to put my code in another class? Do you use other code to make this?
Thanks.
You can make a static variable say : SelectedPlayer,
and assign first player to it!
then you can call the first player through this class,
for example
class GameManager
{
public static PlayerIndex SelectedPlayer{get;set;}
..
..
..
}
and right after the loop in your code, you can say:
GameManager.SelectedPlayer = FirstPlayer;
I hope this helps, if your code cold be clearer that would be easier to help :)
Ok, so to do this properly you're going to have to redesign a little.
First off, you should be checking for a new gamepad input (i.e. you should be exiting the screen only when 'A' has been newly pressed). To do this you should be storing previous and current gamepad states:
private GamePadState currentGamePadState;
private GamePadState lastGamePadState;
// in your constructor
currentGamePadState = new GamePadState();
lastGamePadState = new GamePadState();
// in your update
lastGamePadState = currentGamePadState;
currentGamePadState = GamePad.GetState(PlayerIndex.One);
Really what you need to do is modify your class that deals with input. The basic functionality from your HandleInput function should be moved into your input class. Input should have a collection of functions that test for new/current input. For example, for the case you posted:
public Bool IsNewButtonPress(Buttons buton)
{
return (currentGamePadState.IsButtonDown(button) && lastGamePadState.IsButtonUp(button));
}
Then you can write:
public override void HandleInput(InputState input)
{
if (input.IsNewButtonPress(Buttons.A)
{
this.ExitScreen();
AddScreen(new Background());
}
}
Note: this will only work for one controller. To extend the implementation, you'll need to do something like this:
private GamePadState[] currentGamePadStates;
private GamePadState[] lastGamePadStates;
// in your constructor
currentGamePadStates = new GamePadState[4];
currentGamePadStates[0] = new GamePadState(PlayerIndex.One);
currentGamePadStates[1] = new GamePadController(PlayerIndex.Two);
// etc.
lastGamePadStates[0] = new GamePadState(PlayerIndex.One);
// etc.
// in your update
foreach (GamePadState s in currentGamePadStates)
{
// update all of this as before...
}
// etc.
Now, you want to test every controller for input, so you'll need to generalise by writing a function that returns a Bool after checking each GamePadState in the arrays for a button press.
Check out the MSDN Game State Management Sample for a well developed implementation. I can't remember if it supports multiple controllers, but the structure is clear and can easily be adapted if not.