JavaFX label not updating - javafx

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.

Related

How to use the Vaadin Testbench with Rich Text Area?

I am using Vaadin Testbench (4.1.0-alpha) for designing some integration test for my application (designed in Vaadin 7.6.1).
In a window, I use a rich test area. The idea is to design a test where the value of this rich text element is changed simulating some user behaviour. But now I realize I cannot find any method for change the value of this element, neither get the current value of the element.
I have tested some methods.getHTML() gets the HTML for the component, no the HTML of the designer. getText() gets the list of elements (font colour, background and other options of the element, but not the content).
Then I expect to have specific class methods for retrieving the value. If I explore the class RichTextAreaElement, seems that no method is implemented. All code in this class is:
#ServerClass("com.vaadin.ui.RichTextArea")
public class RichTextAreaElement extends AbstractFieldElement {
}
As you can see, no method is declared.
How can I do a test where a user change the value of this rich text area? It is not implemented?
Hmm yeah, that looks like some work in progress, probably because it's a complex component with all the features it provides. Nonetheless we can workaround the limitations a bit, again making use of chrome developer tools (or similar) and some custom classes to select the components by (actually it's just the gwt-RichTextArea).
Of course this serves just as a starting point and can be further enhanced. Also I'd be very interested to see a more elegant solution if someone finds one...
Structure inspection
Test class
public class RichTextAreaTest extends TestBenchTestCase {
#Before
public void setUp() throws Exception {
System.setProperty("webdriver.chrome.driver", "D:\\Kit\\chromedriver_win32\\chromedriver.exe");
setDriver(new ChromeDriver());
}
#After
public void tearDown() throws Exception {
// TODO uncomment below once everything works as expected
//getDriver().quit();
}
#Test
public void shouldModifyRichTextArea() throws InterruptedException {
// class to identify the editor area by
String editorClass = "gwt-RichTextArea";
// open the browser
getDriver().get("http://localhost:8080/");
// select the first rich text
RichTextAreaElement richTextArea = $(RichTextAreaElement.class).first();
// get the editor section which is where we're writing
WebElement richTextEditorArea = richTextArea.findElement(By.className(editorClass));
// click inside to make it "editable"
richTextEditorArea.click();
// send some keystrokes
richTextEditorArea.sendKeys(" + something else added by selenium");
}
}
Result:
Update for getting the value
If you simply want to get the text, the code below will do the trick:
// switch to the editor iframe
getDriver().switchTo().frame(richTextEditorArea);
// get the <body> section where the text is inserted, and print its text
System.out.println("Text =[" + findElement(By.xpath("/html/body")).getText() + "]");
Output
Text =[Some predefined text + something else added by selenium]
At the end, I was able to obtain the content of the element selecting the first iframe of the page, and searching for the body content. The final code looks like:
String currentWindow = getDriver().getWindowHandle();
getDriver().switchTo().frame(getDriver().findElement(By.tagName("iframe")));
WebElement webelement = this.findElement(By.xpath("/html/body"));
String text = webelement.getText();
getDriver().switchTo().window(currentWindow);
return text;
As I need to switch between the iframe and the window, I am only able to obtain the content of the element, not the element itself. If I return directly the element for future use, an org.openqa.selenium.StaleElementReferenceException: Element belongs to a different frame than the current one - switch to its containing frame to use it exception is obtained.
For changing the text, the solutions is very similar, only use the sendKey functions to first remove existing characters and later add the new text:
String currentWindow = getDriver().getWindowHandle();
getDriver().switchTo().frame(getDriver().findElement(By.tagName("iframe")));
WebElement webelement = this.findElement(By.xpath("/html/body"));
// Remove any previous text.
String previousText = webelement.getText();
for (int i = 0; i < previousText.length(); i++) {
webelement.sendKeys(Keys.DELETE);
}
// Set text.
webelement.sendKeys(text);
getDriver().switchTo().window(currentWindow);

Editable multiline cell in TableView

(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 ;-)

Flex validation popups no longer showing up in popup dialogs?

I am working on an application which has quite a bit of field-validation in it. The validation works great and I am 1000000% sure the validation message popups were appearing earlier. Now I did quite a bit of work and refactoring. One of the things I changed was the way I open up Popups/Dialog. In order to have these centered over the entire application instead of the opening component I refactored the way I open dialogs. I used the source of the Alert as a base for this but extended it quite a bit as I was having other issues (Focus Manager etc.) (I am just mentioning this as I am assuming that my missing popups are related to this).
Here comes the code responsible for opening popups in my application:
public function show(realParent:Sprite,
displayParent:Sprite = null,
closeHandler:Function = null,
moduleFactory:IFlexModuleFactory = null):Dialog {
// Get the parent ...
// If none is set, use the top-level-application.
if (!displayParent) {
var sm:ISystemManager = ISystemManager(FlexGlobals.topLevelApplication.systemManager);
// no types so no dependencies
var mp:Object = sm.getImplementation("mx.managers.IMarshallPlanSystemManager");
if (mp && mp.useSWFBridge())
displayParent = Sprite(sm.getSandboxRoot());
else
displayParent = Sprite(FlexGlobals.topLevelApplication);
}
// Register for close-events, making sure the pop-up is closed.
if (closeHandler != null) {
this.addEventListener(CloseEvent.CLOSE, closeHandler);
}
// Setting a module factory allows the correct embedded font to be found.
if (moduleFactory) {
this.moduleFactory = moduleFactory;
} else if (realParent is IFlexModule) {
this.moduleFactory = IFlexModule(realParent).moduleFactory;
} else {
if (realParent is IFlexModuleFactory) {
this.moduleFactory = IFlexModuleFactory(realParent);
} else {
this.moduleFactory = FlexGlobals.topLevelApplication.moduleFactory;
}
// also set document if parent isn't a UIComponent
if (!parent is UIComponent) {
this.document = FlexGlobals.topLevelApplication.document;
}
}
// Make the dialog center itself relative to the parent.
PopUpManager.addPopUp(this, displayParent, true);
PopUpManager.centerPopUp(this);
return this;
}
What could be responsible for the Validation popups not showing up any more? Where should I look?
Chris
Ok ... so I figgured this out by myself again. I coould bang my head at the wall for taking so long for finding it though.
If I use the Spart forms, the FormItems and Forms themselves can define error text areas in order to output error messages. So as soon as the FormItem posesses a skin part with the id "errorTextDisplay" the error messages go there. I was now expecting that if there was no such part, the old notifications would be used ... nope.
After about 2-3 Hours of messing around with the code of FormItem and it's skins, I noticed that the "contentGroup" explicitly defined an attribute to suppress error tooltyips by setting showErrorTip to false. Simply removing the "errorTextDisplay" from the skin and changing the showErrorTip to true made my popups appear nicely :-)
Hopefully this post might help someone with the same problems.

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 to make QComboBox popup upwards?

my QComboBox-derived class lives in a QGraphicsScene at the bottom end of the (visible) screen - but it pops up downwards, thus out of view.
(How) is it possible to force the popup to open above the widget?
I've tried re-implementing showPopup like this:
void MyComboBox::showPopup()
{
QAbstractItemView *popupView = view();
popupView->move(0,-100);
//popupView->window->move(0,-100);
QComboBox::showPopup();
}
The result is, that the content seems to be shifted, but not the underlying popup object.
I think it might be possible to find a solution with styles as indicated in
this article, but I can't find any Styles control that might be helpful here. I am rather new to C++ as well as Qt, so I might be missing something obvious.
I'd appreciate any help on this matter!
Best regards,
Sebastian
With the information found here, I was able to get it done this way:
void SteuerQComboBox::showPopup() {
QComboBox::showPopup();
QWidget *popup = this->findChild<QFrame*>();
popup->move(popup->x(),popup->y()-this->height()-popup->height());
}
Note that it's crucially important to call the base classes "showPopup" first.
Thanks to everybody who was reading my question and thinking about it!
user1319422's solution isn't bad, but it has two problems.
If your platform has GUI animation, the listbox will animate opening downwards, then is moved above the text box.
If you disable combobox animation (or you don't have it), the call to QComboBox::showPopup() still makes the GUI element start to appear on the screen already. So, moving it there would cause it to flicker as it appears in the first place and moves to the next.
So, to address the first problem, I just switched off animation:
void MyComboBox::showPopup()
{
bool oldAnimationEffects = qApp->isEffectEnabled(Qt::UI_AnimateCombo);
qApp->setEffectEnabled(Qt::UI_AnimateCombo, false);
QComboBox::showPopup();
qApp->setEffectEnabled(Qt::UI_AnimateCombo, oldAnimationEffects);
}
Then, for the second problem, I moved the frame in the Show event:
bool MyComboBox::eventFilter(QObject *o, QEvent *e)
{
bool handled = false;
if (e->type() == QEvent::Show)
{
if (o == view())
{
QWidget *frame = findChild<QFrame*>();
//For some reason, the frame's geometry is GLOBAL, not relative to the QComboBox!
frame->move(frame->x(),
mapToGlobal(lineEdit()->geometry().topLeft()).y() - frame->height());
}
}
/*else if other filters here*/
if (!handled)
handled = QComboBox::eventFilter(o, e);
return handled;
}
if you want to force popup to open above only when it is out of view you can do this:
void SteuerQComboBox::showPopup() {
QComboBox::showPopup();
QWidget *popup = this->findChild<QFrame*>();
if((popup->y() + popup->height()) > this->window()->height())
popup->move(popup->x(),popup->y()-this->height()-popup->height());
}

Resources