How can I set the Font type globally in a JavaFX application?
Is there any solution that I can use? In JavaFX 8 the default Font has changed, and I would like to use the same Font used in JavaFX 2.2.
You can skin your application with CSS as described on the Oracle Website.
Using following syntax you may set the general theme for your application:
.root{
-fx-font-size: 16pt;
-fx-font-family: "Courier New";
-fx-base: rgb(132, 145, 47);
-fx-background: rgb(225, 228, 203);
}
You include the css as followed:
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
Changing the Default Font for a Scene
This is the solution outlinked in nyyrikki's answer.
You can change the default font used for most things in any given scene by applying the following CSS stylesheet to the scene:
.root {
-fx-font: 28px Vivaldi;
}
Substitute whatever settings you require for the -fx-font value according the font definition in the JavaFX CSS reference guide.
Changing the Default Font for an Application
If you want to change the default font used for most things in a JavaFX application, you can override the default style sheet using Application.setUserAgentStylesheet. Using this method you can set the default style for a JavaFX 8 application to the caspian stylesheet which was default for JavaFX 2.2 rather than the modena stylesheet which is default for JavaFX 8. If you want some hybrid of the two default styles or some custom default stylesheet such as AquaFX, then you will need to perform the customization yourself.
Switching Font Rendering Technology
Additionally, on some platforms, JavaFX 2.2 uses a different font rendering mechanism than JavaFX 8, which can account for subtle differences in font rendering between the two. There is an undocumented and unsupported command line switch which can be used to switch between font rendering mechanisms in JavaFX 8, but I don't know what the switch is off-hand and, even if I did, I wouldn't recommend deploying an application using the switch as it is unsupported.
FWIW, if you want to make the font change programmatically (no external css files involved), you can make a "global" change by using the .setStyle() method on the top parent node.
Example, I wrote a quick GUI (a bare bones testing framework) that both a Windows and a Mac user needed to run (and I'm writing on Linux/Ubuntu). The Mac user complained that the fonts were too small. So I added the following:
String os = System.getProperty("os.name","generic").toLowerCase(Locale.US);
if (os.indexOf("mac") > 0) {
root.setStyle("-fx-font-size: 14pt");
}
In this case, root is the Parent node in the Scene instantiation. All nodes connected to root will share this font size setting, unless the setting is overwritten.
Just a TornadoFX example
package bj
import tornadofx.*
class MyView : View() {
override val root = vbox {
button("天地玄黄")
button("宇宙洪荒")
}
}
class MyStylesheet : Stylesheet() {
init {
root {
fontFamily = "Noto Sans CJK SC Regular"
}
}
}
class MyApp : App(MyView::class, MyStylesheet::class)
fun main(args: Array<String>) {
launch<MyApp>(*args)
}
Related
I have eclipse 3.7 indigo; I installed gwt plugin and its designer; The problem is (time after time) when I add new widget X to composite the
palette (keeps widget selected)
components (doesn't show the new widget in the tree)
properties (doesn't show the new widget properties)
...so I cannot select another widget unless I resize the whole eclipse application to force its GUI repaint :(
It seems like palette and other managers don't get report "widget was added from windowbuilder" or similar :(
Moreover, I cannot edit widget's text if I have input method as "System" which is the default on btw so the only one input method which works is "X Input Method" but anyways it doesn't solve the mentioned focus regain problem;
That makes eclipse indigo really hard to use; So my question is... how to fix that?
p.s.
eclipse 3.7 (indigo)
gwt plugin - https://dl.google.com/eclipse/plugin/archive/3.6.0/3.7
gwt designer - http://dl.google.com/eclipse/inst/d2gwt/latest/3.7
gwt sdk 2.2
jdk 1.7
jre 1.7
OS Linux x64
Thanks
I had to do my own research concerning the issue; I noticed there is some kind of "jobs order conflict" or similar with the default constructor based code style as :
public class MyTestUI extends Composite {
private FlowPanel flowPanel;
public MyTestUI() {
flowPanel = new FlowPanel();
initWidget(flowPanel);
}
}
...so, as a workaround, I had to play with code generator as;
window -> preferences -> windowbuilder -> gwt
(combobox) method name for new statements : initComponents
variable generation : field
statement generation : flat
just to avoid having in-constructor init as a result I have code generated as :
public class MyTestUI extends Composite {
private FlowPanel flowPanel;
public MyTestUI() {
initComponents();
}
private void initComponents() {
flowPanel = new FlowPanel();
initWidget(flowPanel);
}
}
...btw there is a problem with focus regain if input method is "System" and initComponents() method generated first time; so before starting adding widgets I had to select "X input method" to avoid synch-ed jobs; So "X input method" needs to be the default one, as I can get it :)
EDIT :
The effect I faced very looks like bug 388170; So I tried to modify eclipse.ini argument as
-Djava.awt.headless=true
It seems like the headless helps a bit but anyways eclipse sometimes does hang when using windowbuilder especially DnD :P
Anyways I want to point I faced the mentioned issue first time cause similar windows x32 eclipse indigo version works pretty fine with gwt;
p.s.
The solution is not final (the hang problem still occurs on DnD evens) and I am still looking for a more optimal one; So do comment if you have some helpful tips or ideas;
I'm trying to implement an Editor with hint text functionality for a Xamarin.Forms project. This is trivial in Android, because the underlying EntryEditText control has a Hint property. In iOS, the implementation is a bit more complex because the UITextView class does not implement hint text.
I don't like the technique, "set text to the placeholder, clear it if typing starts, return it if typing ends and the text is blank". It means I have to do extra work to tell if the control's blank, and there's a lot of fiddling with the text color involved. But I've been having so much trouble I'm going to have to resort to it. Maybe someone can help me with this.
I started with the answer to Placeholder in UITextView. I started a new Xamarin iOS project and stumbled through a rough Obj-C to C# conversion, and it worked great with a minor change: the Font property of the UITextView isn't initialized yet in the constructor, so I had to override AwakeFromNib() to set the placeholder label's font. I tested it and it worked, so I brought that file into a Xamarin Forms project, and things started getting a little nutty.
The first problem is it turns out apparently MonoTouch has some slight API differences in Xamarin Forms, such as using some types like RectangleF instead of CGRect. This was obvious, if not unexpected. I've been wrestling with some other differences for the past few days, and can't seem to overcome them in a way that makes me happy. Here's my file, trimmed down significantly because I've been trying all kinds of debugging things:
using System;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using MonoTouch.CoreGraphics;
using System.Drawing;
namespace TestCustomRenderer.iOS {
public class PlaceholderTextView : UITextView {
private UILabel _placeholderLabel;
private NSObject _notificationToken;
private const double UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION = 0.25;
private string _placeholder;
public string Placeholder {
get {
return _placeholder;
}
set {
_placeholder = value;
if (_placeholderLabel != null) {
_placeholderLabel.Text = _placeholder;
}
}
}
public PlaceholderTextView() : base(RectangleF.Empty) {
Initialize();
}
private void Initialize() {
_notificationToken = NSNotificationCenter.DefaultCenter.AddObserver(TextDidChangeNotification, HandleTextChanged);
_placeholderLabel = new UILabel(new RectangleF(8, 8, this.Bounds.Size.Width - 16, 25)) {
LineBreakMode = UILineBreakMode.WordWrap,
Lines = 1,
BackgroundColor = UIColor.Green,
TextColor = UIColor.Gray,
Alpha = 1.0f,
Text = Placeholder
};
AddSubview(_placeholderLabel);
_placeholderLabel.SizeToFit();
SendSubviewToBack(_placeholderLabel);
}
public override void DrawRect(RectangleF area, UIViewPrintFormatter formatter) {
base.DrawRect(area, formatter);
if (Text.Length == 0 && Placeholder.Length > 0) {
_placeholderLabel.Alpha = 1;
}
}
private void HandleTextChanged(NSNotification notification) {
if (Placeholder.Length == 0) {
return;
}
UIView.Animate(UI_PLACEHOLDER_TEXT_CHANGED_ANIMATION_DURATION, () => {
if (Text.Length == 0) {
_placeholderLabel.Alpha = 1;
} else {
_placeholderLabel.Alpha = 0;
}
});
}
public override void AwakeFromNib() {
base.AwakeFromNib();
_placeholderLabel.Font = this.Font;
}
protected override void Dispose(bool disposing) {
base.Dispose(disposing);
if (disposing) {
NSNotificationCenter.DefaultCenter.RemoveObserver(_notificationToken);
_placeholderLabel.Dispose();
}
}
}
}
A notable change here is relocation of the label's initialization from DrawRect() to the constructor. As far as I can tell, Xamarin never lets DrawRect() be called. You'll also note I'm not setting the Font property. It turned out in the iOS MonoTouch project, sometimes the parent's font was null and it's illegal to set the label's font to null as well. It seems at some point after construction Xamarin sets the font, so it's safe to set that property in AwakeFromNib().
I wrote a quick Editor-derived class and a custom renderer so Xamarin Forms could render the control, the Renderer is slightly of note because I derived from NativeRenderer instead of EditorRenderer. I needed to call SetNativeControl() from an overridden OnModelSet(), but peeking at the assembly viewer showed that EditorRenderer makes some private calls I'll have to re-implement in mine. Boo. Not posted because this is already huge, but I can edit it in if needed.
The code above is notable because the placeholder isn't visible at all. It looks like in iOS-oriented MonoTouch, you typically initialize a control with a frame, and resizing is a rare enough circumstance you can assume it doesn't happen. In Xamarin Forms, layout is performed by layout containers, so a constructor-provided frame is irrelevant. However, the size of the label is intended to be set in the constructor, so it ends up having negative width. Whoops.
I assumed this could be solved by moving instantiation of the label into AwakeFromNib(), or at least sizing it there. This is when I discovered that for some reason, AwakeFromNib() isn't called in the control. Welp. I tried to find an equivalent callback/event that happened late enough for the bounds to be set, but couldn't find anything on the iOS side. After trying many, many things, I noticed the custom renderer received property change events for the Xamarin Forms Model side of this mess. So, if I listen for Height/Width change events, I can then call a method on the label to give it a reasonable size based on the current control. That exposed another problem.
I cannot find a way to set the label's font to match the UITextView's font. In the constructor, the Font property is null. This is true in both the iOS and Xamarin Forms project. In the iOS project, by the time AwakeFromNib() is called, the property is initialized and all is well. In the XF project, it's never called, and even when I pull stunts like invoking a method from a 5-second delayed Task (to ensure the control is displayed), the property remains null.
Logic and iOS documentation dictates the default value for the font should be 17-point Helvetica. This is true for the placeholder label if I fudge the size so it's visible. It is not true for the UITextView control, though since it reports its font as null I'm unable to see what the font actually is. If I manually set it all is well, of course, but I'd like to be able to handle the default case. This seems like a bug; the box seems to be lying about its font. I have a feeling it's related to whatever reason the Xamarin.Forms.Editor class doesn't have a Font property.
So I'm looking for the answer to two questions:
If I'm extending an iOS control in XF to add a subview, what is the best way to handle sizing that subview? I've found Height/Width changes raise events in the renderer, is this the only available way?
When the property has not been set by a user, is the Font of a UITextView in Xamarin Forms ever set to a non-null value? I can live with a requirement that this control requires the font to be explicitly set, but it's yucky and I'd like to avoid it.
I'm hoping I've missed something obvious because I started barking up the wrong trees.
If I'm extending an iOS control in XF to add a subview, what is the
best way to handle sizing that subview? I've found Height/Width
changes raise events in the renderer, is this the only available way?
This is the only way I know of since the exposed elements of the renderer are so limited.
When the property has not been set by a user, is the Font of a
UITextView in Xamarin Forms ever set to a non-null value? I can live
with a requirement that this control requires the font to be
explicitly set, but it's yucky and I'd like to avoid it.
No, the Font is not assigned a default non-null value.
I'm drawing a text using GDI+. I recently noticed that this text is automatically scaled when the DPI is changed. Is there a way to make the GDI+ text drawing independent of the DPI? E.g. I want to draw a text up to 20 pixels, regardless of the DPI. Is it possible? How to do this?
Below is a sample code. I want to draw the first text with a constant size, regardless of the DPI, and the second text normally:
case WM_PAINT:
{
inherited::WndProc(message);
Canvas->Brush->Style = bsSolid;
Canvas->Brush->Color = clWhite;
Canvas->FillRect(ClientRect);
// get GDI+ graphics from canvas
Gdiplus::Graphics graphics(Canvas->Handle);
// set text rendering hint
graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintSystemDefault);
std::auto_ptr<Gdiplus::Font> pFont(new Gdiplus::Font(Canvas->Handle, Font->Handle));
std::auto_ptr<Gdiplus::SolidBrush> pBrush(new Gdiplus::SolidBrush(Gdiplus::Color(255, 0, 0, 0)));
std::auto_ptr<Gdiplus::StringFormat> pFormat(new Gdiplus::StringFormat());
Gdiplus::FontFamily fontFamily;
pFont->GetFamily(&fontFamily);
std::auto_ptr<Gdiplus::Font> pFont2(new Gdiplus::Font(&fontFamily, pFont->GetSize(),
pFont->GetStyle(), Gdiplus::UnitPixel));
Gdiplus::Unit test = pFont->GetUnit();
Gdiplus::Unit test2 = pFont2->GetUnit();
pFormat->SetAlignment(Gdiplus::StringAlignmentNear);
pFormat->SetLineAlignment(Gdiplus::StringAlignmentNear);
Gdiplus::StringFormatFlags flags = Gdiplus::StringFormatFlagsBypassGDI;
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsDirectionRightToLeft);
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsDirectionVertical);
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsNoWrap);
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsNoClip);
pFormat->SetFormatFlags(flags);
pFormat->SetTrimming(Gdiplus::StringTrimmingEllipsisCharacter);
pFormat->SetHotkeyPrefix(Gdiplus::HotkeyPrefixNone);
std::wstring text = L"This is a sample code";
Gdiplus::Unit prevPageUnit = graphics.GetPageUnit();
try
{
graphics.SetPageUnit(Gdiplus::UnitPixel);
// draw text
graphics.DrawString(text.c_str(), text.length(), pFont2.get(), Gdiplus::RectF(ClientRect.Left,
ClientRect.Top, ClientWidth, ClientHeight), pFormat.get(), pBrush.get());
}
__finally
{
graphics.SetPageUnit(prevPageUnit);
}
// draw text 2
graphics.DrawString(text.c_str(), text.length(), pFont.get(), Gdiplus::RectF(ClientRect.Left,
ClientRect.Top + 25, ClientWidth, ClientHeight), pFormat.get(), pBrush.get());
return;
}
Regards
I wanted to mention something, slightly unrelated to your question. You shouldn't be using Graphics.DrawString in GDI+ anymore. It was deprecated in .NET 2. Instead Microsoft created TextRenderer.DrawString.
There are two ways of drawing text in .NET:
GDI+ (graphics.MeasureString and graphics.DrawString)
GDI (TextRenderer.MeasureText and TextRenderer.DrawText)
In .NET 1.1 everything used GDI+ for text rendering. But there were some problems:
There are some performance issues caused by the somewhat stateless nature of GDI+, where device contexts would be set and then the original restored after each call.
The shaping engines for international text have been updated many times for Windows/Uniscribe and for Avalon (Windows Presentation Foundation), but have not been updated for GDI+, which causes international rendering support for new languages to not have the same level of quality.
So they knew they wanted to change the .NET framework to stop using GDI+'s text rendering system, and use GDI. At first they hoped they could simply change:
graphics.DrawString
to call the old DrawText API instead of GDI+. But they couldn't make the text-wrapping and spacing match exactly as what GDI+ did. So they were forced to keep graphics.DrawString to call GDI+ (compatiblity reasons; people who were calling graphics.DrawString would suddenly find that their text didn't wrap the way it used to).
A new static TextRenderer class was created to wrap GDI text rendering. It has two methods:
TextRenderer.MeasureText
TextRenderer.DrawText
Note:
- TextRenderer is a wrapper around GDI
- graphics.DrawString is still a wrapper around GDI+
Then there was the issue of what to do with all the existing .NET controls, e.g.:
Label
Button
TextBox
They wanted to switch them over to use TextRenderer (i.e. GDI), but they had to be careful. There might be people who depended on their controls drawing like they did in .NET 1.1. And so was born "compatible text rendering".
By default controls in application behave like they did in .NET 1.1 (they are "compatible").
You turn off compatibility mode by calling:
Application.SetCompatibleTextRenderingDefault(false);
This makes your application better, faster, with better international support. To sum up:
SetCompatibleTextRenderingDefault(true) SetCompatibleTextRenderingDefault(false)
======================================= ========================================
default opt-in
bad good
the one we don't want to use the one we want to use
uses GDI+ for text rendering uses GDI for text rendering
graphics.MeasureString TextRenderer.MeasureText
graphics.DrawString TextRenderer.DrawText
Behaves same as 1.1 Behaves *similar* to 1.1
Looks better
Localizes better
Faster
It's also useful to note the mapping between GDI+ TextRenderingHint and the corresponding LOGFONT Quality used for GDI font drawing:
TextRenderingHint mapped by TextRenderer to LOGFONT quality
======================== =========================================================
ClearTypeGridFit CLEARTYPE_QUALITY (5) (Windows XP: CLEARTYPE_NATURAL (6))
AntiAliasGridFit ANTIALIASED_QUALITY (4)
AntiAlias ANTIALIASED_QUALITY (4)
SingleBitPerPixelGridFit PROOF_QUALITY (2)
SingleBitPerPixel DRAFT_QUALITY (1)
else (e.g.SystemDefault) DEFAULT_QUALITY (0)
Samples
Here's some comparisons of GDI+ (graphics.DrawString) verses GDI (TextRenderer.DrawText) text rendering:
GDI+: TextRenderingHintClearTypeGridFit, GDI: CLEARTYPE_QUALITY:
GDI+: TextRenderingHintAntiAlias, GDI: ANTIALIASED_QUALITY:
GDI+: TextRenderingHintAntiAliasGridFit, GDI: not supported, uses ANTIALIASED_QUALITY:
GDI+: TextRenderingHintSingleBitPerPixelGridFit, GDI: PROOF_QUALITY:
GDI+: TextRenderingHintSingleBitPerPixel, GDI: DRAFT_QUALITY:
i find it odd that DRAFT_QUALITY is identical to PROOF_QUALITY, which is identical to CLEARTYPE_QUALITY.
See also
UseCompatibleTextRendering - Compatible with whaaaaaat?
Sorting it all out: A quick look at Whidbey's TextRenderer
MSDN: LOGFONT Structure
AppCompat Guy: GDI vs. GDI+ Text Rendering Performance
GDI+ Text, Resolution Independence, and Rendering Methods.
Or - Why does my text look different in GDI+ and in GDI?
This is what works for me.
using namespace Gdiplus;
HDC hDC = ::GetDC( NULL );
int nDPI = ::GetDeviceCaps( hDC, LOGPIXELSY );
::ReleaseDC( NULL, hDC );
REAL fFontHeight = 96 / (REAL)nDPI * 8;
FontFamily fontFamily( L"Arial" );
Gdiplus::Font font( &fontFamily, fFontHeight, UnitPixel );
REAL fMeasuredFontHeight = font.GetHeight( &gr );
It turns out that Gdiplus::Font, despite being specified in pixels, uses the user's DPI setting to adjust the resulting font (even when the font is to be used to draw in a bitmap!). The standard DPI of 96 is a good value to use determine the correct ratio to adjust the font size.
In the above snippet, the font height sought was 8 pixels high.
fMeasuredFontHeight remains nearly constant (at approx. 12), through all DPI settings.
I noticed that when I run JavaFX application on JVM 7 and JVM 8 I get different default skins. How I can set the default skin to be same on every JVM?
You can set the default skin:
#Override
public void start(Stage stage) throws Exception {
....
setUserAgentStylesheet(STYLESHEET_CASPIAN);
....
}
http://fxexperience.com/2013/01/modena-new-theme-for-javafx-8/
The default stylesheet for JavaFX 2 is caspian.css. You can find it in jfxrt.jar under com.sun.javafx.scene.control.skin.caspian. This changed with JavaFX 8 and I believe the default stylesheet is named modena.css. In order to get a common stylesheet, you will have to either define your own or copy one of the defaults into your project.
You can also run with -Djavafx.userAgentStylesheetUrl=caspian on the command line.
You can set your own skin by adding a style sheet.
scene.getStylesheets().add(
getClass().getResource("my-skin.css").toExternalForm());
Unfortunately there is no default style sheet. Maybe browsing in jfxrt.jar might yield something.
How to change font in all dialog forms in a visual c++ application?
I want to set Tahoma style.
Thanks.
You can set the font for a dialog in the resource it's created from. I believe that'll change the font on all the standard controls as well. If you have custom controls, you'll have to do additional work.
Note that if you want to have the font match the default UI font for the computer, then you can use a virtual font like "MS Shell Dlg 2" which will be mapped to Tahoma on XP, and Segoe UI on Vista+.
Replacing font in each dialog of your application would be rather tedious job.
You can employ MFC to do it for you.
Check InitInstance of your app. Look at AfxEnableControlContainer();
It is being called woithout any parameter even though AfxEnableControlContainer is declared as
void AFX_CDECL AfxEnableControlContainer(COccManager* pOccManager=NULL);
COccManager is a very interesting class and is used when has occ ( OLE custom controls) support, managing OLE container and site classes. All MFC applications are created by default with occ support. If you do not see AfxEnableControlContainer in the code generated by wizard, you do not have occ support enabled.
Anyway, instead using default occ implementation, use own and change it to change the font.
Derive class from COccManager. In this sample I call it CDlgOccManager. Override virtual PreCreateDialog:
virtual const DLGTEMPLATE* PreCreateDialog(_AFX_OCC_DIALOG_INFO* pOccDialogInfo,
const DLGTEMPLATE* pOrigTemplate);
In the implementation:
const DLGTEMPLATE* CDlgOccManager::PreCreateDialog(_AFX_OCC_DIALOG_INFO* pOccDialogInfo, const DLGTEMPLATE* pOrigTemplate)
{
CDialogTemplate RevisedTemplate(pOrigTemplate);
// here replace font for the template
RevisedTemplate.SetFont(_T("Tahoma"), -16);
return COccManager::PreCreateDialog (pOccDialogInfo, (DLGTEMPLATE*)RevisedTemplate.Detach());
}
Now you are changin font for all dialogs. Remember changing AfxEnableControlContainer call:
PROCESS_LOCAL(CDlgOccManager, pManager);
BOOL CDlgFontChangeApp::InitInstance()
{
AfxEnableControlContainer(pManager.GetData());
.
.
.
}
DO not forget to
#include "DlgOccManager.h"
For new verion of the MFC include afxdisp.h for older, occimpl.h for COccManager.
I just noticed something. It is not a blunder but it needs an explanation.
I have kept this code in my repository for a very, very, very long time.
It was a time when DLLs kept all data as global, making data available to all modules that loaded this dll. In order to force data to be stored in TLS area, I used PROCESS_LOCAL macro that expands to invoking CProcessLocal class that is still alive.
You can remove this macro and replace it with:
BOOL CDlgFontChangeApp::InitInstance()
{
CDlgOccManager* pManager = new CDlgOccManager();
AfxEnableControlContainer(pManager);
.
.
.
}