I have a bit of an issue here..
I'm trying to have a svgpath be a background image by using it in a stackpane. I have a set-up like this:
Where that grey triangle is a svgpath (just a basic one for testing purposes). Now that SVG is located inside an hbox like so:
class mView : View() {
override val root = vbox {
label("test text") {
//label styles
}
hbox {
stackpane {
//first blue box
}
stackpane {
//second green box
svgpath("M600 0 L350 800 L900 800 Z") {
addClass(UIStyles.bgImagesStyle)
}
}
stackpane {
//third red box
}
}
}
}
And this all works well and good, but I need to scale the svgpath down a bit..
svgpath("M600 0 L350 800 L900 800 Z") {
addClass(UIStyles.bgImagesStyle)
scaleX = .4
scaleY = .4
}
and then this happens:
I need the green box to adhere to the new, scaled-down bounds of the svgpath. Is there a way to "update" the width/height of the stackpane to the new bounds?
Thank you for any help!
Related
I have a vertical stack view that contains a number of horizontal stack views. How can I create a 1px separator line between the horizontal stackviews?
You can create a Separator View:
class SeparatorView: UIView {
init() {
super.init(frame: .zero)
setUp()
}
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setUp() {
backgroundColor = .gray
}
override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height:0.5)
}
}
And add it to your StackView in between the horizontal views:
stackView.addArrangedSubview(horizontalView)
stackView.addArrangedSubview(SeparatorView())
This will create a small gray line that separates the views.
just add in a UIView with a 1-2px width and the same height as each of the horizontal stack views in between the two middle most controls in the horizontal stack view. Assuming that there is no top or bottom spacing it would give the impression of a vertical line without breaks, or if you don't mind breaks in the vertical line then don't worry about removing top or bottom spacing.
OR
You could leverage the fact that UIStackView can take subviews, and just work out the centre x, and with a y of 0, add in a 2px wide UIView as a subview of the UIStackView.
Something like:
UIStackView sv = new UIStackView();
UIView ViewLine = new UIView();
ViewLine.Frame = new CGRect(CentreX, 0 , 2f , heightofstackview );
sv.AddSubview();
The solution for centering any subview within a parent is usually simple, however, it doesn't seem to work in my case.
I'm working with a UICollectionView and have added a Header class programmatically. I have this constructor, where I also try to center the label within the screen:
[Export("initWithFrame:")]
public Header(System.Drawing.RectangleF frame) : base(frame)
{
label = new UILabel
{
Frame = new System.Drawing.RectangleF(frame.Size.Width / 2, 50, 200, 50),
BackgroundColor = UIColor.Clear,
TextColor = UIColor.White,
Font = UIFont.FromName("HelveticaNeueLTStd-ThCn", 35f),
Text = DateTime.Now.ToString("Y")
};
AddSubview(label);
}
And I initialize the class inside the UICollectionViewSource 's constructor like this:
public MyCollectionViewDataSource(MainController mainController, DateTime currentDate)
{
try
{
controller = mainController;
new Header(new RectangleF(0, 0, (float)mainController.View.Frame.Size.Width, 200));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + ex.StackTrace);
}
}
What exactly am I missing because this usually works in other instances but seems to fail here?
This is what it looks like :
I found an explanation here iOS Layout Gotchas by Adam Kemp which helped me resolve this issue.
The first solution
One very common mistake I made was adding the layout definition code in the constructor, instead of doing it in the rightful place : the LayoutSubviews override in this case.
Giving the label the frame size in the constructor assumes a static size set at the time of construction, which may later change depending on the screen size.
The second solution
He explains that :
Frame sets the position of a view within its parent while Bounds is in the coordinate system of the view itself (not its parent).
So, to center the UILabel, I used bounds and center together and this worked for me.
[Export("initWithFrame:")]
public Header(CGRect bounds) : base(bounds)
{
label = new UILabel
{
BackgroundColor = UIColor.Clear,
TextColor = UIColor.White,
Font = UIFont.FromName("HelveticaNeueLTStd-ThCn", 35f),
Text = DateTime.Now.ToString("Y"),
TextAlignment = UITextAlignment.Center
};
rectangle = bounds;
AddSubview(label);
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
label.Bounds = new CGRect (rectangle.Size.Width / 2, 50, 200, 50);
label.Center = new PointF((float)rectangle.Size.Width/2,50);
}
I'm working with google cardboard in unity.
In my main scene I have a skybox with an image as texture.
How can I get the color of the pixel I'm looking?
The skybox is an element of mainCamera, that is child of "Head".
I put also GvrReticle as child of head; is it useful for my purpose?
Thanks
Basically you wait for the end of the frame so that the camera has rendered. Then you read the rendered data into a texture and get the center pixel.
edit Be aware that if you have a UI element rendered in the center it will show the UI element color not the color behind.
private Texture2D tex;
public Color center;
void Awake()
{
StartCoroutine(GetCenterPixel());
}
private void CreateTexture()
{
tex = new Texture2D(1, 1, TextureFormat.RGB24, false);
}
private IEnumerator GetCenterPixel()
{
CreateTexture();
while (true)
{
yield return new WaitForEndOfFrame();
tex.ReadPixels(new Rect(Screen.width / 2f, Screen.height / 2f, 1, 1), 0, 0);
tex.Apply();
center = tex.GetPixel(0,0);
}
}
Since my interaction with computer, I have seen only menu bar in horizontal direction only. The menuitem of such menubar will be popping downwards. In JavaFX it is easy to create such a menu with a horizontal menubar.
Is it possible to create a vertical menubar in JavaFX ? Also I want the menuitems to be popped out either to left or right, not downwards.
Can I implement such a menu of my desire ? Someone please help.
You can leverage the MenuButton for that:
#Override
public void start(Stage primaryStage) {
MenuButton m = new MenuButton("Eats");
m.setPrefWidth(100);
m.setPopupSide(Side.RIGHT);
m.getItems().addAll(new MenuItem("Burger"), new MenuItem("Hot Dog"));
MenuButton m2 = new MenuButton("Drinks");
m2.setPrefWidth(100);
m2.setPopupSide(Side.RIGHT);
m2.getItems().addAll(new MenuItem("Juice"), new MenuItem("Milk"));
VBox root = new VBox();
root.getChildren().addAll(m, m2);
Scene scene = new Scene(root, 300, 250);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
where the style.css is
.menu-button {
-fx-skin: "com.sun.javafx.scene.control.skin.MenuButtonSkin";
-fx-background-color: red, green, green, lightgreen;
-fx-background-insets: 0 0 -1 0, 0, 1, 2;
-fx-background-radius: 0;
-fx-padding: 0.0em; /* 0 */
-fx-text-fill: -fx-text-base-color;
}
/* TODO workaround for RT-19062 */
.menu-button .label { -fx-text-fill: -fx-text-base-color; }
.menu-button:focused {
-fx-color: beige;
-fx-background-color: -fx-focus-color, -fx-outer-border, -fx-inner-border, -fx-body-color;
-fx-background-insets: -1.4, 0, 1, 2;
-fx-background-radius: 0;
}
.menu-button:hover {
-fx-color: darkgreen;
}
.menu-button:armed {
-fx-color: greenyellow;
}
These selectors are partially taken and overriden from caspian.css. Change the color preferences as your needs and you can also remove the arrow of the buttons through css.
The drawback of this approach is the difficulty of making nested menu items.
I am trying to style my JavaFX linechart but I have some trouble with the legend.
I know how to change the legend color of a line chart in the css file:
.default-color0.chart-series-line { -fx-stroke: #FF0000, white; }
.default-color1.chart-series-line { -fx-stroke: #00FF00, white; }
.default-color2.chart-series-line { -fx-stroke: #0000FF, white; }
.default-color0.chart-line-symbol { -fx-background-color: #FF0000, white; }
.default-color1.chart-line-symbol { -fx-background-color: #00FF00, white; }
.default-color2.chart-line-symbol { -fx-background-color: #0000FF, white; }
But this is not enough for my purposes. I have three or more colored toggle buttons and a series of data for every button. The data should be displayed in the same color the button has after I have selected the button. This should be possible with a multiselection of the buttons, so that more than one series of data can be displayed simultaneously.
For the chart lines I have managed it by changing the style after I clicked the button:
..
dataList.add(series);
..
series.getNode().setStyle("-fx-stroke: rgba(" + rgba + ")");
If I deselect the button I remove the data from the list.
dataList.remove(series);
That is working fine for the strokes, but how can I do the same for the legend?
You can see an example below. First I clicked the red button, thus the stroke and the legend is red (default-color0). After that I clicked the blue button. Here you can see the problem. The stroke is blue but the legend is green, because default color1 is used and I do not know how to change the legend color.
I ran into this issue as well. The issue seems to be that when data series are added to the chart, the legend isn't updated at the same time, so when you lookup components with that seriesN style class they don't exist yet. Came up with a work-around that detects when the legend items are created so that dynamic styling can be added to them.
I added a ListChangeListener to the chart legend's "getChildrenUnmodifiable()" ObservableList, which in turn adds a ListChangeListener to each of the legend's children as they get added. From within this listener, we can tell when new items are being added to the legend (or removed). This allow us to then make the dynamic style changes.
for (Node n : lineChart.getChildrenUnmodifiable())
{
if (n instanceof Legend)
{
final Legend legend = (Legend) n;
// remove the legend
legend.getChildrenUnmodifiable().addListener(new ListChangeListener<Object>()
{
#Override
public void onChanged(Change<?> arg0)
{
for (Node node : legend.getChildrenUnmodifiable())
{
if (node instanceof Label)
{
final Label label = (Label) node;
label.getChildrenUnmodifiable().addListener(new ListChangeListener<Object>()
{
#Override
public void onChanged(Change<?> arg0)
{
//make style changes here
}
});
}
}
}
});
}
}
For future reference, this problem can be solved by wrapping your relevant code in a call to Platform.runLater(). For example:
LineChart<Number, Number> plot;
....
Platform.runLater(() -> {
Node nl = plot.lookup(".default-color0.chart-series-line");
Node ns = plot.lookup(".default-color0.chart-line-symbol");
nl.setStyle("-fx-stroke: #333;");
ns.setStyle("-fx-background-color: #333, white;");
});
It seems that this guy is able to lookup the nodes used for legend using their class, and then calling setStyle() on those nodes. (I don't think his problem is relevant for yours)
This solution is based on #Chris' solution
if (checkCombo.getCheckModel().isChecked(0)) {
lineChart.getData().add(seriesTest1);
changeColorSeries(lineChart.getData().size() - 1, "darkgreen");
}
if (checkCombo.getCheckModel().isChecked(3)) {
lineChart.getData().add(seriesTest2);
changeColorSeries(lineChart.getData().size() - 1, "darkred");
}
private void changeColor(int position, String color) {
Platform.runLater(() -> {
Node nl = lineChart.lookup(".default-color" + position + ".chart-series-line");
Node ns = lineChart.lookup(".default-color" + position + ".chart-line-symbol");
Node nsl = lineChart.lookup(".default-color" + position + ".chart-legend-item-symbol");
nl.setStyle("-fx-stroke: " + color + ";");
ns.setStyle("-fx-background-color: " + color + ", white;");
nsl.setStyle("-fx-background-color: " + color + ", white;");
});
}
After digging a lot through google with no success I finally found a lean way to update the legend colors according line color through this method:
private void setLegendItemColor(String shop, String color, Legend lg) {
for (Node n : lg.getChildren()) {
Label lb = (Label) n;
if (lb.getText().contains(shop)) {
lb.getGraphic().setStyle("-fx-background-color:" + color + ";");
}
}
}
So you just need to call the method setLegendItemColor() when you´re going to update the chart lines to update the legend label symbols to the correspondent color.