Editable multiline cell in TableView - javafx

(There already is a question regarding this but it has no answer and the comment isn't helpful either.)
I've got a TableView and I'd like to have a column with multiline labels that I can edit. Ideally, the behaviour would be like a TextFieldTableCell but with multiline support:
It displays text like a label.
When clicked, it transforms into a TextField (or in this case, a TextArea) so the text can be edited.
I haven't found a solution for this yet. The only workaround I've got right now is put a TextArea as the cell's "graphic":
descriptionTableColumn.setCellFactory(param -> new TableCell<Attachment, String>() {
#Override
protected void updateItem(String item, boolean empty) {
if (empty) {
setGraphic(null);
} else {
TextArea area = new TextArea(item);
area.setMinHeight(USE_COMPUTED_SIZE);
area.setPrefHeight(USE_COMPUTED_SIZE);
area.setMaxHeight(USE_COMPUTED_SIZE);
setGraphic(area);
}
}
});
(Code to listen to the text changes is missing here; it doesn't trigger the OnEditCommit event.)
However, the TextArea is always rendered as a normal TextArea with a border and white background. I can live with that. But the area also always renders with a certain height (about 180px) even when it's empty, even though I set USE_COMPUTED_SIZE.
So the question is:
Is there a way to get the ideal behaviour, similar to the TextFieldTableCell?
If not, is there a way to have the TextArea only use as much height as needed?

Ok, the basic idea is to copy the TextFieldTableColumn and adjust its behavior to create a TextAreaTableColumn. I hacked a small working example implementation together: https://gist.github.com/eckig/30abf0d7d51b7756c2e7
Usage:
TableColumn<?, ?> column = new TableColumn<>();
column.setCellValueFactory(...);
column.setCellFactory(TextAreaTableCell.forTableColumn()); // add StringConverter if neccessary
tableView.getColumns().add(column);
But, there are still some things left which need to be implemented / some tuning:
Adjust prefRowCount to show only the necessary amount of rows.
Maybe adjust prefColumnCount?
Because the "Enter" Key gets consumed for a new-line, I had to add a Save Button to commit the edit. This is somewhat ugly, but for now I do not have a better idea.
But hopefully you get the idea ;-)

Related

Rg.Plugins.Popup is not closing when background is clicked in Xamarin.Forms

I have used rg.plugins.popup in my application. I have updated the xamarin forms (version="2.5.0.121934"). Now the outer background is clicked it is not closed. I used to close the popup many ways, but not closed, I tried the below code:
this.CloseWhenBackgroundIsClicked = false;
protected override bool OnBackgroundClicked()
{
Navigation.PopPopupAsync();
return false;
}
OnBackgroundClicked is not calling. How to fix this issue?
I don't understand if you know that the correct code is: this.CloseWhenBackgroundIsClicked = true; (not false), but if this is not working you could try a workaround until this problem is solved.
Basically, add a Grid as the root of your PopupPage and add a Colorless BoxView with a TapGestureRecognizer as a child of the Grid, then just add the actual content as another child of the Grid and set the Tapped of the TapGestureRecognizer to the "BackgroundClicked" code.
Hope it helps!
At first, I put all my StackLayout in a ScrollView and I had the same problem. Then I remove the ScrollView and it works.
Maybe a little late answer. But i think someone will need it.
You should override the backbutton from MainActivity.
//add this to inside the Android MainActivity
public async override void OnBackPressed()
{
if (Rg.Plugins.Popup.Popup.SendBackPressed(base.OnBackPressed))
{
await PopupNavigation.Instance.PopAsync();
}
else
{
// Do something if there are not any pages in the `PopupStack`
}
}
I had the same problem, in my case it was about not understanding how this plugin works.
First time I used the popup I placed a StackLayout on the center of the screen with this.CloseWhenBackgroundIsClicked = true and it worked pretty well, the problem was when I placed a GridLayout with columns 10*, 80*, 10* and rows 10*, 80*, 10*. my content was going in grid.rows(1), grid.columns(1). the other lines and columns were just borders.
If I clicked the borders it would'nt work because I was touching the grid sides and not the actually background.
The solution was change Grid for stacklayout and center it.

JavaFX label not updating

I have a label (called display) set up in javaFX, and I am trying to fill it with a char[]. For some reason, the display.setText() method is updating the contents, but not displaying in the window (it still has the filler text "label"). If anyone could help, that would be great. Here is my code:
public void display()
{
System.out.println("display");
String toPrint="";
for(int r=0;r<grid.length;r++)
{
for(int c=0;c<grid.length;c++)
toPrint+=grid[r][c];
toPrint+="\n";
}
System.out.println("");
display.setText(toPrint);
System.out.println(display.getText());
}
I assume the last line of your code prints out the expected result. The reason for your problem is probably outside the code you have shown here. There may also be a misunderstanding on your side. Calling display.setText does not immediately render the new text. This will be done with the next pulse. So if there is something else in your code which prevents the next pulse (blocks the UI-thread) then the new text will never be shown. This is of course just a guess because you do not provide enough code to confirm this guess.

JavaFX, change css tablecell on sort

I have to change the styleclass of a TableCell in function of the data displayed, for example: if the value of a cell is the same in two contiguous rows, the cell has to be highlighted (i.e.: background red). This must work both adding data to the table and sorting by any column.
To do so, on sorting, I added a listener to tableview.getSortOrder() and in its onChange method the logic to do what I described above. By example:
public void onChanged(ListChangeListener.Change<? extends TableColumn> change) {
if (change.getList().size() > 0) {
Platform.runLater(new Runnable() {
#Override
public void run() {
/* set some css on tableview cells */
}
});
}
}
The problem is that doing so css changes are applied on the next refresh of the table not immediately. My suspects are on doing this inside Platform.runLater but I need it to have the data sorted as they should be, before changing styles.
Did I do anything wrong? Does exist a better way to do what I described?
You could do that if you have a specific css file for it and add it.
final String css = getClass.getResource("the_css.css").toExternalForm();
and add this in the Platform.runLater:
scene.getStylesheet.add(css);
remove if necessary with:
scene.getStylesheet.remove(css);
Not exactly sure if this does the trick, but it should change the background color right away and not after a refresh. i hope it's helping you in the right direction.

How to detect QTableWidget scroll source (code itself/user (wheel)/user (scrollbar))?

I'm writing a program using Qt 4.8 that displays a table (QTableWidget) filled with filenames and file's params. First an user adds files to the list and then clicks process. The code itself updates the contents of the table with simple progress description. I want the table by default to be scrolled automatically to show the last processed file and that code is ready.
If I want to scroll it by hand the widget is being scrolled automatically as soon as something changes moving the viewport to the last element. I want to be able to override the automated scroll if I detect that it was the user who wanted to change view.
This behavior can be seen in many terminal emulator programs. When there's a new line added the view is scrolled but when user forces the terminal to see some previous lines the terminal does not try to scroll down.
How could I do that?
Solution:
I created an object which filters event processed by my QTableWidget and QScrollBar embedded inside. If I spot the event that should turn off automatic scrolling I just set a flag and stop scrolling view if that flag is set.
Everything is implemented inside tableController class. Here are parts of three crucial methods.
bool tableController::eventFilter(QObject* object, QEvent* event)
{
switch (event->type())
{
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::Wheel:
case QEvent::MouseButtonDblClick:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
_autoScrollEnabled = false;
default:
break;
}
return QObject::eventFilter(object, event);
}
void tableController::changeFile(int idx)
{
[...]
if (_autoScrollEnabled)
{
QTableWidgetItem* s = _table.item(_engine.getLastProcessed(), 1);
_table.scrollToItem(s);
}
[...]
}
void tableController::tableController()
{
[...]
_autoScrollEnabled = true;
_table.installEventFilter(this);
_table.verticalTableScrollbar()->installEventFilter(this);
[...]
}
Thanks for all the help. I hope somebody will find it useful :)
Subclass QTableWidget and overload its wheelEvent. You can use the parameters of the supplied QWheelEvent object in order to determine if the user scrolled up or down.
Then use a simple boolean flag which is set (or reset) in your wheelEvent override. The method which is responsible for calling scrollToBottom() should then consider this boolean flag.
You will have to find a way to figure out when to set or reset that flag, e.g. always set it when the user scrolls up and reset it when the user scrolls down and the currently displayed area is at the bottom.
connect(_table->view()->verticalScrollBar(), &QAbstractSlider::actionTriggered, this, [this](int) {
_autoScrollEnabled = false;
});

How do I stop the formatting (bold etc) being lost when a user deletes a whole line in Flex tlf textflow control

I am using text layout framework textflow in Flex 3 to get embedded images. In the edit field for the application the user can apply formatting. This all works fine except if the user deletes all the text they have entered and then starts typing again then the formatting is lost.
I'm using
//setup default formatting
currentCF.fontWeight = FontWeight.NORMAL;
_currentCF.fontStyle = FontPosture.NORMAL;
_currentCF.textDecoration = TextDecoration.NONE;
_currentCF.color = 0; //black
IEditManager(textFlow.interactionManager).applyLeafFormat(_currentCF);
To setup the initial formatting then similar code to apply the formatting when the user changes it.
So how can I stop the user from 'deleting' the formatting if they delete all the text?
Thanks,
Nigel
OK. Not sure what is going on with the span elements that allows the formatting to be deleted. But I've worked around it by capturing the backspace\delete keys and setting the current formatting onto the textflow and this has worked around it.
protected function onKeyUp(event:KeyboardEvent):void
{
//check if backspacing or deleting
if (event.keyCode == 8 || event.keyCode == 46)
{
//check if they have removed all text which can lose the formatting
if (textFlow.textLength == 1)
{
//apply the current formatting
editMan.selectAll();
IEditManager(textFlow.interactionManager).applyLeafFormat(_currentCF);
}
}
}

Resources