Codename One Picker text spinning after item is selected - codenameone

I have a CN1 application that uses three pickers inside a container.
One of the pickers just contains small strings like "1x" , "2x" , etc.
Every time an item is selected on the running application, the selected text spins really fast, what looks kind of odd.
I have tried setting padding and margin to zero, and set SmoothScrolling to false.
picker.setSmoothScrolling(false);
All to no avail.
Is there ant solution to it? Many thanks in advance ..
Here is the relevant part of the code:
private final Picker pickerInterval = new Picker();
private final Picker pickerDayOrMonth = new Picker();
private final Picker pickerFinal = new Picker();
String stringPickerInterval = "repetir a cada ..";
pickerInterval.setType(Display.PICKER_TYPE_STRINGS);
pickerInterval.setUIID("DatePickerDialog");
pickerInterval.setStrings("1","2","3","4","5","6","6","8","9","10","11","12",stringPickerInterval);
pickerInterval.setSelectedString(stringPickerInterval);
pickerInterval.addActionListener((e) -> {
if (!pickerInterval.getSelectedString().equals(stringPickerInterval)) {
pickerInterval.setUIID("DatePickerDialogSelected");
} else {
pickerInterval.setUIID("DatePickerDialog");
}
});
String stringPickerDayOr = "dias ou semanas ou ...";
pickerDayOrMonth.setType(Display.PICKER_TYPE_STRINGS);
pickerDayOrMonth.setUIID("DatePickerDialog");
pickerDayOrMonth.setStrings("Dia(s)", "Semana(s)", "Mes(es)","Ano(s)" , stringPickerDayOr);
pickerDayOrMonth.setSelectedString(stringPickerDayOr);
pickerDayOrMonth.addActionListener((e) -> {
if (!pickerDayOrMonth.getSelectedString().equals(stringPickerDayOr)) {
pickerDayOrMonth.setUIID("DatePickerDialogSelected");
} else {
pickerDayOrMonth.setUIID("DatePickerDialog");
}
});
String stringPickerFinal = "freqüência das repetições ..";
pickerFinal.setType(Display.PICKER_TYPE_STRINGS);
pickerFinal.setUIID("DatePickerDialog");
pickerFinal.setStrings("1 x","2 x","3 x","4 x","5 x","6 x","6 x","8 x","9 x","10 x","11 x","12 x" , stringPickerFinal);
pickerFinal.setSelectedString(stringPickerFinal);
pickerFinal.addActionListener((e) -> {
if (!pickerFinal.getSelectedString().equals(stringPickerFinal)) {
pickerFinal.setUIID("DatePickerDialogSelected");
} else {
pickerFinal.setUIID("DatePickerDialog");
}
});
container = new Container(new GridLayout(1, 3));
container.setUIID("ContainerPicker");
container.add(pickerInterval).add(pickerDayOrMonth).add(pickerFinal);

Related

Xamarin Forms and Calendar in c#

I use to Xamarin Calendar my project of C#.
https://github.com/lilcodelab/Xamarin.Plugin.Calendar
I want to mark several undefined dates, because I want to download them from a text file
Example file:
5/5/2020|Name
As you can see in the Binding events part, the event is bind with Events collection, you could create several event object like:
MyEvent event1=new MyEvent(name,description);
MyEvent event2=new MyEvent(name,description);
and add them into the list:
events.add(event1);
events.add(event2);
In the end I solved it this way
enter code here
String path = #"actividades.txt";
var filePath = Path.Combine(DEFAULTPATH, path);
string texto1;
System.IO.StreamReader sr = new System.IO.StreamReader(filePath);
Events = new EventCollection();
while (!sr.EndOfStream)
{
texto1 = sr.ReadLine();
string[] words = texto1.Split('|');
DateTime fecha = DateTime.Parse(words[0]);
d = fecha.Day;
m = fecha.Month;
y = fecha.Year;
if (words.Length > 2)
Events.Add(new DateTime(y, m, d), new List<Evento> { new Evento { Nombre = words[2], Tipo = words[1], colorF = words[3] } });
}

Slow UI construction

I am making list of logos inside a BoxLayout.Y_AXIS. it is taking too long to be shown. The logos are loaded from the Storage. I am quite new on Codenameone, less than three months, and the code I use is below:
public void makeList( ) {
this.membersContainer.removeAll();
int membersNo = this.members.size();
ToastBar.showInfoMessage("Βρέθηκαν " + membersNo);
for( Map.Entry<String,String[]> entry: this.members.entrySet() ) {
Button b = new Button();
b.setUIID("Label");
b.setUnselectedStyle( this.itemStyle);
Object[] s = entry.getValue();
try {
ToastBar.showInfoMessage( s[0].toString() );
b.setIcon( EncodedImage.create( Storage.getInstance().createInputStream( s[0].toString()) ) );
b.addActionListener(e -> {
new MemberGui ( entry.getKey(), s[0].toString(), s[1].toString(), s[2].toString(), s[3].toString(), this ).show();
});
}
catch(IOException ex) {
ToastBar.showErrorMessage(ex.getMessage());
}
this.membersContainer.add(b);
}
}
I am wondering is there any other way to create this List of logos? Right now it takes more than 40 seconds to show this screen on iphone 7 plus.
thank you.
Use InfiniteContainer and only load 10 logos at a time. See https://www.codenameone.com/javadoc/com/codename1/ui/InfiniteContainer.html

Codename One - Validator of PickerComponent

In the following code, the Validator of the PickerComponent "date" is never executed on the Simulator with "GooglePixel2.skin", instead is executed with "iPhoneX.skin". Why?
In the log there isn't the string "Validator of date executed" after picking a date on Android (in the simulator), instead that string is continuosly logged on iPhone (in the simulator). Is my code incorrect?
I tried to follow this example: https://www.codenameone.com/javadoc/com/codename1/ui/layouts/TextModeLayout.html
public void show(Form backForm) {
TextModeLayout textModeLayout = new TextModeLayout(4, 1);
Container inputPersonData = new Container(textModeLayout);
TextComponent name = new TextComponent().label("Nome");
TextComponent surname = new TextComponent().label("Cognome");
PickerComponent gender = PickerComponent.createStrings("Maschio", "Femmina", "altro");
PickerComponent date = PickerComponent.createDate(new Date());
Validator val = new Validator();
val.addConstraint(name, new LengthConstraint(2));
val.addConstraint(surname, new LengthConstraint(2));
val.addConstraint(date, new Constraint() {
#Override
public boolean isValid(Object value) {
Log.p("Validator of date executed");
boolean res = false;
if (value instanceof Date) {
Calendar birthday = Calendar.getInstance();
birthday.setTime((Date) value);
Calendar nowLess13years = Calendar.getInstance();
nowLess13years.setTime(new Date());
nowLess13years.add(Calendar.YEAR, -13);
if (birthday.before(nowLess13years) || birthday.equals(nowLess13years)) {
res = true;
}
}
return res;
}
#Override
public String getDefaultFailMessage() {
return "You must be at least 13 years old";
}
});
inputPersonData.add(name);
inputPersonData.add(surname);
inputPersonData.add(gender);
inputPersonData.add(date);
add(inputPersonData);
super.show();
Log.p("Registry Form shown correctly");
}
That seems to be a bug in the validator code and picker component. It works for me only after I edit one of the fields regardless of the skin. I've fixed this to bind correctly everywhere.

AS3 Separating Arrays for different items

I have a function that creates a new value inside an associative array.
var array:Array = new Array(new Array());
var i : int = 0;
function personVelgLand(evt:MouseEvent)
{
for(i = 0; i < personListe.dataProvider.length; i++)
{
if(txtPersonVelg.text == personListe.dataProvider.getItemAt(i).label)
{
personListe.dataProvider.getItemAt(i).reise = array;
personListe.dataProvider.getItemAt(i).reise.push(landListe.selectedItem.land);
}
}
}
What happens is that the 'array' array which becomes 'personListe.dataProvider.getItemAt(i).reise' applies to every item in the list. I want it so that each time the function runs that the .reise only applies to the item chosen and not all of them.
EDIT:
I did this:
personListe.dataProvider.getItemAt(i).reise = new Array(array);
And now they are not the same but now each item in the list can not have multiple .reise values...
EDIT 2: dataProvider is nothing it would work just as fine without it. .reise is created in the function I originally posted it creates .reise in the object getItemAt(i).
personListe is a list which the users add their own items to by the use of a input textfield. It is given by this function:
function regPerson(evt:MouseEvent)
{
regPersoner.push(txtRegPerson.text);
personListe.addItem({label:regPersoner});
regPersoner = new Array();
txtRegPerson.text = "";
}
EDIT 3 : The user can register names which turn in to labels in a list. There is also list with 3 countries, Spain, Portugal and England. The user can then register a country to a person they select. Thats when I want to create the .reise inside the "name" items in the first list which contains the countries they have selected. I want every name to be able to select multiple countries which then will be created in the element .reise inside the item that holds their name. This would be easy if I could use strings. But later I plan to have the user type in a country and then something that would show every user that have selected that country. That is why the countries need to be stored as arrays inside the "name" items..
You should first create a class for the User data that you are modelling. You already know all the properties.
The user can register names
The user can then register a country to a person they select.
able to select multiple countries
Such a class could look like this:
package
{
public class User
{
private var _name:String;
private var _countries:Array;
public function User(name:String)
{
_name = name;
_countries = [];
}
public function get name():String
{
return _name;
}
public function get countries():Array
{
return _countries;
}
public function set countries(value:Array):void
{
_countries = value;
}
}
}
Now create a DataProvider, fill it with objects of that class and use it for the list as described here:
import fl.controls.List;
import fl.data.DataProvider;
var users:List = new List();
users.dataProvider = new DataProvider([
new User("David"),
new User("Colleen"),
new User("Sharon"),
new User("Ronnie"),
new User("James")]);
addChild(users);
users.move(150, 150);
In order to get a label from a User object, define a labelFunction
import fl.controls.List;
import fl.data.DataProvider;
var users:List = new List();
users.labelFunction = userLabelFunction;
function userLabelFunction(item:Object):String
{
return item.name;
}
users.dataProvider = new DataProvider([
new User("David"),
new User("Colleen"),
new User("Sharon"),
new User("Ronnie"),
new User("James")]);
addChild(users);
users.move(150,150);
This way you do not have to add a label property that you don't want in your class.
Selecting a name means selecting a user. The list of countries associated to the name should show up in a second List.
The DataProvider of that List remains constant, a list of all the available countries.
import fl.controls.List;
import fl.data.DataProvider;
// list of users
var users:List = new List();
addChild(users);
users.move(150,150);
users.labelFunction = userLabelFunction;
function userLabelFunction(item:Object):String
{
return item.name;
}
users.dataProvider = new DataProvider([
new User("David"),
new User("Colleen"),
new User("Sharon"),
new User("Ronnie"),
new User("James")]);
// lsit of countries
var countries:List = new List();
addChild(countries);
countries.move(550,150); // adjut position as desired
countries.dataProvider = new DataProvider([
{label:"a"},
{label:"b"},
{label:"c"},
{label:"d"},
{label:"e"},
{label:"f"}]);
Now all you have to do is to wire it all up. If a user is selected, select his countries in the countries list. If a country is selected, add that to the currently selected users list of countries. That could look somethign like this:
users.addEventLsitener(Event.CHANGE, onUserSelected);
function onUserSelected(e:Event):void
{
countries.selectedItems = users.selectedItem.countries;
}
countries.addEventLsitener(Event.CHANGE, onCountrySelected);
function onCountrySelected(e:Event):void
{
users.selectedItem.countries = countries.selectedItems;
}
The full code could look like this. I did not test this, but you get the idea.
// list of users
var users:List = new List();
addChild(users);
users.move(150,150);
users.labelFunction = userLabelFunction;
function userLabelFunction(item:Object):String
{
return item.name;
}
users.dataProvider = new DataProvider([
new User("David"),
new User("Colleen"),
new User("Sharon"),
new User("Ronnie"),
new User("James")]);
// list of countries
var countries:List = new List();
addChild(countries);
countries.move(550,150); // adjut position as desired
countries.dataProvider = new DataProvider([
{label:"a"},
{label:"b"},
{label:"c"},
{label:"d"},
{label:"e"},
{label:"f"}]);
// events
users.addEventLsitener(Event.CHANGE, onUserSelected);
function onUserSelected(e:Event):void
{
countries.selectedItems = users.selectedItem.countries;
}
countries.addEventLsitener(Event.CHANGE, onCountrySelected);
function onCountrySelected(e:Event):void
{
users.selectedItem.countries = countries.selectedItems;
}
From what I understand this seems to work except for the fact that the names are already provided when the program starts. What I want is that the user adds the name themselves while the program is running.
You can add new items with the methods provided by the DataProvider class, like addItem() for example. Just add new User objects.

How can I use NLog's RichTextBox Target in WPF application?

How can I use RichTextBox Target in WPF application?
I don't want to have a separate window with log, I want all log messages to be outputted in richTextBox located in WPF dialog.
I've tried to use WindowsFormsHost with RichTextBox box inside but that does not worked for me: NLog opened separate Windows Form anyway.
A workaround in the mean time is to use the 3 classes available here, then follow this procedure:
Import the 3 files into your project
If not already the case, use Project > Add Reference to add references to the WPF assemblies: WindowsBase, PresentationCore, PresentationFramework.
In WpfRichTextBoxTarget.cs, replace lines 188-203 with:
//this.TargetRichTextBox.Invoke(new DelSendTheMessageToRichTextBox(this.SendTheMessageToRichTextBox), new object[] { logMessage, matchingRule });
if (System.Windows.Application.Current.Dispatcher.CheckAccess() == false) {
System.Windows.Application.Current.Dispatcher.Invoke(new Action(() => {
SendTheMessageToRichTextBox(logMessage, matchingRule);
}));
}
else {
SendTheMessageToRichTextBox(logMessage, matchingRule);
}
}
private static Color GetColorFromString(string color, Brush defaultColor) {
if (defaultColor == null) return Color.FromRgb(255, 255, 255); // This will set default background colour to white.
if (color == "Empty") {
return (Color)colorConverter.ConvertFrom(defaultColor);
}
return (Color)colorConverter.ConvertFromString(color);
}
In your code, configure the new target like this below example:
I hope it helps, but it definitely does not seem to be a comprehensive implementation...
public void loading() {
var target = new WpfRichTextBoxTarget();
target.Name = "console";
target.Layout = "${longdate:useUTC=true}|${level:uppercase=true}|${logger}::${message}";
target.ControlName = "rtbConsole"; // Name of the richtextbox control already on your window
target.FormName = "MonitorWindow"; // Name of your window where there is the richtextbox, but it seems it will not really be taken into account, the application mainwindow will be used instead.
target.AutoScroll = true;
target.MaxLines = 100000;
target.UseDefaultRowColoringRules = true;
AsyncTargetWrapper asyncWrapper = new AsyncTargetWrapper();
asyncWrapper.Name = "console";
asyncWrapper.WrappedTarget = target;
SimpleConfigurator.ConfigureForTargetLogging(asyncWrapper, LogLevel.Trace);
}
If you define a RichTextBoxTarget in the config file, a new form is automatically created. This is because NLog initializes before your (named) form and control has been created. Even if you haven't got any rules pointing to the target. Perhaps there is a better solution, but I solved it by creating the target programatically:
using NLog;
//[...]
RichTextBoxTarget target = new RichTextBoxTarget();
target.Name = "RichTextBox";
target.Layout = "${longdate} ${level:uppercase=true} ${logger} ${message}";
target.ControlName = "textbox1";
target.FormName = "Form1";
target.AutoScroll = true;
target.MaxLines = 10000;
target.UseDefaultRowColoringRules = false;
target.RowColoringRules.Add(
new RichTextBoxRowColoringRule(
"level == LogLevel.Trace", // condition
"DarkGray", // font color
"Control", // background color
FontStyle.Regular
)
);
target.RowColoringRules.Add(new RichTextBoxRowColoringRule("level == LogLevel.Debug", "Gray", "Control"));
target.RowColoringRules.Add(new RichTextBoxRowColoringRule("level == LogLevel.Info", "ControlText", "Control"));
target.RowColoringRules.Add(new RichTextBoxRowColoringRule("level == LogLevel.Warn", "DarkRed", "Control"));
target.RowColoringRules.Add(new RichTextBoxRowColoringRule("level == LogLevel.Error", "White", "DarkRed", FontStyle.Bold));
target.RowColoringRules.Add(new RichTextBoxRowColoringRule("level == LogLevel.Fatal", "Yellow", "DarkRed", FontStyle.Bold));
AsyncTargetWrapper asyncWrapper = new AsyncTargetWrapper();
asyncWrapper.Name = "AsyncRichTextBox";
asyncWrapper.WrappedTarget = target;
SimpleConfigurator.ConfigureForTargetLogging(asyncWrapper, LogLevel.Trace);

Resources