Here is my test:
import gtk.Main;
import gtk.MainWindow;
import gtk.Label;
void main(string[] args)
{
Main.init(args);
auto window = new MainWindow("My Window");
window.add(new Label("Label1"));
window.show();
Main.run();
}
When I replace Main.show() with Main.showAll() it works as expected, however I can't find any documentation for either function here: http://api.gtkd.org/src/gtk/MainWindow.html What is the difference between these two methods and where can I find documentation?
These links from official GTK+ documentation should help: gtk_widget_show, gtk_widget_show_all. In short, show shows only the widget it is called on, and show_all, being applied to a container, shows all widgets in this container recursively.
GtkD has very poor and nearly impossible to use API docs, though this seems to be a problem not of GtkD but of D tools. The methods you are referring to are defined on GtkWidget class, but unfortunately the page about gtk.Widget is empty (mostly).
Related
What is the correct way of handling tap events with the new androidx.wear.watchface libraries? I was doing this with the now deprecated android.support:wearable libraries without any problem with Java (using onTapCommand). Now, everything seems to be quite different, especially since the documentation and examples seem to be available only in Kotlin. Also, I can't find any example which properly shows how the functions are used.
The documentation mentions setTapListener, TapListener. And then there are the functions onTap, onTapEvent and onTapCommand. This seems very confusing.
Could somebody put here a small example? Or point me to a working example on the internet?
Any help much appreciated!
Implementing this seemed to work for me
https://developer.android.com/reference/androidx/wear/watchface/WatchFace.TapListener
My code:
class WatchFaceRenderer(...): Renderer.CanvasRenderer(...), WatchFace.TapListener {
override fun onTapEvent(tapType: Int, tapEvent: TapEvent, complicationSlot: ComplicationSlot?) {
if (tapType == TapType.UP)
// do something
invalidate()
}
}
class Service : WatchFaceService() {
override suspend fun createWatchFace(
surfaceHolder: SurfaceHolder,
watchState: WatchState,
complicationSlotsManager: ComplicationSlotsManager,
currentUserStyleRepository: CurrentUserStyleRepository
): WatchFace {
val renderer = WatchFaceRenderer(
context = applicationContext,
surfaceHolder = surfaceHolder,
watchState = watchState,
currentUserStyleRepository = currentUserStyleRepository,
canvasType = CanvasType.SOFTWARE,
)
return WatchFace(WatchFaceType.ANALOG, renderer).setTapListener(renderer)
}
}
From all the searching and reading it’s clear that I need to call Platform.runLater() to change the GUI. It also appears I need to use the Runnable interface. Perhaps I should also use Tasks?
But I can’t figure out how exactly I should use them. Plus, I’m not sure which class I should put them in. I’m super new to JavaFX.
My trial JavaFX project has only a Label and a TextField. Label contains a question and the TextField is for answering. Simple enough.
I ran into the problem here:
The answer checking method is in a separate class. I can’t figure out how I can access the components of the GUI/FXML and change them. The methods in the other classes are static while the components of the GUI/FXML are non-static.
Since my actual project would have many quizzes, I'm keen on using separate classes for checking answers.
Only 3 small classes are relevant here:
The “Launcher” class which contains the main method.
The “ViewController” class for the FXML file as well as some methods.
The “Ans” class which has a method to check the answer input.
In which class should I put the Platform.runLater()? And how would the code be?
I’ll just share the code of the “Ans” and the “ViewController” classes.
Ans (The background works are supposed to happen in this file. In the comments, I've mentioned what I want to do but unable to do. For example, I want to set the Label text from there but I can't. Since I have no idea how to do it I've just put a System.out.Println there. In the comments next to it, I've mentioned what I actually want to do.)
package com.dan.ans;
import com.dan.qn.Qn;
import com.dan.view.ViewController;
public class Ans {
public static void checkAns() {
// Checks if the ans is correct.
if (ViewController.getTextFieldInput().equalsIgnoreCase(Qn.getAns())) {
System.out.println("Correct!"); // Here I want the label to say 'Correct!' rather than it be print out in the console.
Qn.setQuestion(); // This gets the next question from the database. But again, I don't know how to make the changes show on the screen. (In the actual code I'd have a separate Label for each of these things)
} else { // Runs if it's not correct.
System.out.println("Incorrect!"); // Here I want the label to say 'Incorrect' rather than it be print out in the console.
}
}
}
ViewController
package com.dan.view;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import com.dan.ans.Ans;
import com.dan.qn.Qn;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class ViewController implements Initializable {
private static String textFieldInput; // I don't know how to access the typed info in the textField from another class. So I store it here and get it from it.
// This is the getter I use for it. (See above)
public static String getTextFieldInput() {
return textFieldInput;
}
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
Qn.setQuestion(); // This method is in the Qn class. It retrieves data from the db file and keeps them in variables.
label.setText(Qn.getQn()); // This sets the label's text using the retrieved data. So you see the first question when the program opens.
}
// Event Listener on TextField[#textField].onAction
public void enter(ActionEvent event) throws IOException {
textFieldInput = textField.getText(); // Stores the typed info in the variable to be accessed from elsewhere.
Ans.checkAns(); // Runs the checkAns to check if the typed answer is correct or not.
}
}
The “Launcher” method just looks like any method with a main class. So I haven’t shared its code here.
Could someone please show me how I can update the components in the GUI from other classes such as “Ans”? I’m pretty sure I should use Platform.runLater() and Runnable. Also may be Tasks. I’ve seen several examples but it’s not clear how I can use it this context.
Thanks a lot in advance! :)
It's not really particularly clear what the issue is here. The natural (to me, anyway) approach would simply be to make the checkAnswer(...) method a method that simply "does what it says on the box", i.e. that takes an answer as a parameter, checks it, and returns a value to the caller indicating if it is correct.
That way you can also avoid all the ugly static hacks.
public class Ans {
public boolean checkAns(String answer) {
// not really sure what Qn is here, but you can also clean this up and
// get rid of the static methods
if (answer.equalsIgnoreCase(Qn.getAns()) {
// not sure if this really belongs here?
Qn.setQuestion(); // really takes no parameters? Sets it to what, then?
return true ;
} else {
return false ;
}
}
}
And then in your controller, you can just do
public class ViewController implements Initializable {
private Ans ans ;
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
ans = new Ans();
// ...
}
// ...
public void enter(ActionEvent event) {
if (ans.checkAns(textField.getText())) {
// update UI to show answer was correct, etc
} else {
// update UI to show answer was incorrect...
}
}
// ...
}
Note how this allows you to maintain proper separation of concerns: the Ans class doesn't need to know anything at all about the UI (which it should not know about at all), and all the UI-specific code is encapsulated in the controller class where it belongs.
It's not really clear why you are asking about Platform.runLater(...) and using Task, since none of the code you posted appears to involve any background threads (i.e. none of this code seems to take an appreciable amount of time to run). If, for example, the checkAns(...) method was doing some remote lookup and did take time to run, you would execute it in a Task and update the UI from the task's onSucceeded handler. See, e.g. Using threads to make database requests. Your question really seems to be more about basic OO design and how to define the relationships between different objects, though; I don't think you are actually asking about threading at all.
I'm coding in IntelliJ IDEA. When debugging my application, I can't use some default method implementations in Watches.
Here is a condensed example:
public class Friendship {
interface Friend {
default void sayHiTo(Friend friend) {
System.out.println("Hi, " + friend.hashCode());
}
default int amountOfHands() {
return 2;
}
}
public static class BasicFriend implements Friend {
int numberOfFaces() {
return 1;
}
}
public static void main(String[] args) {
System.out.println("Put a breakpoint here");
}
}
In main() method I put a breakpoint and set up three watches:
// Default interface method with dependency
new BasicFriend().sayHiTo(new BasicFriend())
// Default interface method without dependency
new BasicFriend().amountOfHands()
// Class method
new BasicFriend().numberOfFaces()
The first watch throws NoSuchMethodException complaining that method Friendship$BasicFriend.sayHiTo() doesn't exist.
The second watch runs successfully, but strangely it reports a boxed object
{java.lang.Integer#537} "2" instead of just a primitive 2.
The third watch reports a primitive 1, just as expected.
Why is the first watch not working? Is this a bug? Is this actually IDE related? Is it because of some conceptual flaw of default methods? Should it be working as I want it to in the first place? Is the strange result of the second watch somehow related to the issue in the first watch?
Prior to JDK 8u40, default and static interface methods were not supported by JDI (Java Debugger Interface), JDWP (Java Debugger Wire Protocol) and JDB (the standard Java debugger). This is bug JDK-8042123, which is recorded as fixed in 8u40 and a corresponding blurb appears in the 8u40 release notes.
Update to 8u40 or later to fix this issue, at least on the JDK side.
From the bug description, it looks like debugger-side changes are also required, to avoid casting com.sun.jdi.InterfaceType objects to com.sun.jdi.ClassType, but instead call InterfaceType.invokeMethod() directly.
In the specific case of IntelliJ, Suseika confirmed in a comment that 14.1.2 has mostly fixed the issue (except the unexpected boxing), though Mike Kobit still experiences this problem on that version with a ClassCastException suggestive of the incorrect cast above.
I’m developing a JavaFX application on Eclipse Kepler using the built-in FX library from Java SDK1.7.0_45. I want to display a background image in a scene. Following the tutorial provided in the Java documentation, following code should work:
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
Scene scene = new Scene(grid, 300, 275);
primaryStage.setScene(scene);
scene.getStylesheets().add(Main.class.getResource("Login.css").toExternalForm());
primaryStage.show();
}
}
My CSV file looks like this:
.root {
-fx-background-image: url("background.jpg");
}
But I just get a blank screen instead. I have 3 files in the src/application folder: background.jpg, Main.java and Login.css.
I have tried adding a backslash, putting the image into a separate folder, providing an absolute path, providing several types of images, using ../application/background.jpg, changing the code to file:background.jpg, providing the URL directly into the code and dismissing the CSS file, using an imageview instead, ..... but nothing works.
I've taken a look at several other stackoverflow links, all seemed to fail:
JavaFX How to set scene background image (renders a blank screen)
Setting background image by javafx code (not css) exception)
Cannot load image in JavaFX
and many more.
The strange thing is, when I supply an image from a server as a hyperlink, everything works fine. Supplying the path to a local file never works though. What am I doing wrong? Can somebody show me how to display a local image? Is this a bug?
This worked fine for me with a .png, the only noticeable difference I had as opposed to you, was that I split up the .css file, and my background.png into a sub-package of the main one. Example:
my directory structure looks as follows:
sotestproject ----|
|
|---package sotestProject ---SOTestProject.java
|
|
|
|
package sotestProject.style
|
|---Login.css
|
|---background.png
using this breakdown, the following files with code successfully produced a background with an image:
SoTestProject.java:
package sotestproject;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
/**
*
* #author William
*/
public class SOTestProject extends Application {
#Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
Scene scene = new Scene(grid, 300, 275);
primaryStage.setScene(scene);
scene.getStylesheets().add(SOTestProject.class.getResource("style/Login.css").toExternalForm());
primaryStage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Login.css:
.root {
-fx-background-image: url("background.png");
}
And then obviously my background.png is in the same directory as the .css file. The main 'change' in code is to note that with the scene.getStyleSheet() I used a reference to style/ instead of just the resource.
I hope this helps!
One thing to note: I'm compiling against the 32-bit jdk 7.0_45. That shouldn't make any difference, but there it is.
Partly thanks to the answer from WillBD, I decided to ditch Eclipse Kepler and start all over in Netbeans. I used the exact same code I provided in my question and now everything works just fine. I guess this is a bug between JavaFX and Eclipse Kepler.
Image file must be in the 'bin/application' directory and add your css definitions to the 'src/application/filename.css'
I've had the same problem in NetBeans and tried basically everything. Eventually, I discovered that the file extension "jpg" was written in capital letters in this "project hierarchy box" on the left side of NetBeans.
I changed that part of my code to all capital letters and tadaaa everything worked just fine.
I'm a beginner of both gtk and GtkD.
Now, I'm trying to get input from keyboard with reference to this .
But, It seems that three years have made some changes in Toolkits.
I wrote code below. However, I got strange values of ev in callback function.
I could not see any prospect of resolution with going alone.
So, could you show me where to modify?
I appreciate you in advance, and also your patient with my poor English.
I'm using gtkD-2.1.1 and gtk+3.2.3.
this is the full code:
import std.stdio;
import gtkc.gdktypes;
import gtk.MainWindow;
import gtk.Widget;
import gdk.Event;
import gtk.Main;
class Window : MainWindow{
immutable width = 200;
immutable height = 200;
this(){
super("input test");
setDefaultSize(width,height);
setEvents(EventMask.KEY_PRESS_MASK); // Actually I don't know how this works
auto callback_func = cast(bool delegate(Event,Widget))&get_key; // I doubt this cast
this.addOnKeyPress(callback_func);
showAll();
}
bool get_key(GdkEventKey* ev, Widget widget){
writefln("sender %s", widget);
writefln("type %x",ev.type);
writefln("window* %x",ev.window);
writefln("send_event %x",ev.sendEvent);
writefln("time %x",ev.time);
writefln("state %x",ev.state);
writefln("keyval %x",ev.keyval);
writefln("length %x",ev.length);
writefln("gchar* %x",ev.string);
writefln("hardware_keycode %x",ev.hardwareKeycode);
writefln("group %x",ev.group);
writefln("is_modifier %x\n",ev.bitfield0);
return true;
}
}
void main(string[] args){
Main.init(args);
auto win = new Window();
Main.run();
}
Yes, that cast is wrong. I guess that Signature with GdkEventKey* is outdated. Change your get_key to take an Event and you should get proper results:
...
auto call = &get_key;
...
bool get_key(Event e, Widget widget){
GdkEventKey* ev = e.key();
...
I have never done anything with GtkD, and this is just the result of some glances over the docs. So, it's probably not best practice, but it should get you back on the road.