I recently asked a question about translucent components causing odd artifacts from seemingly not updating properly. The answer I received caused the artifacts to go away, but at the cost of translucency.
The solution was to- for every translucent component- also call the setOpaque(false) function. This way, Swing knew that it needed to redraw the background behind those components.
However, this came at the cost of the translucency that I was trying to achieve. It caused the components to become transparent instead.
The premise is this: I am designing the GUI for a chat client, and a feature request was to have a background. I successfully got the background working by following a code snippet for extending the JPanel class, but then I wanted the components to allow the background to show. After setting their translucency, remnants of updated components were being displayed where they shouldn't have been. I came here and got my problem solved, but now I've got a new problem. So here we are.
So, here is what I've surmised:
-Calling the setOpaque(false) function for each desired component and NOT setting a translucent color does not achieve what I want.
-Setting a translucent color and NOT calling setOpaque(false) allows the translucent background to show, but causes artifacts, putting me back at square one.
So I need some middle ground between transparent with no artifacts, and translucent with artifacts. Namely, I want a translucent background (not completely transparent) that has no artifacts.
It seems like I'm going to need to override the JFrame to cause it to repaint all its components, regardless of the opacity. Unless there's something I'm missing.. which is why I'm here!
Thanks!
(Here's a link to the original question, with a picture for reference: Java Swing - Translucent Components causing Artifacts)
One option would be to override the components and draw the background yourself:
class TranslucentLabel extends JLabel {
public TranslucentLabel(String text) {
super(text);
setOpaque(false);
}
#Override
public void paintComponent(Graphics g) {
g.setColor(new Color(255, 0, 0, 64));
Insets insets = getInsets();
g.fillRect(insets.left, insets.top,
getWidth() - insets.left - insets.right,
getHeight() - insets.top - insets.bottom);
super.paintComponent(g);
}
}
EDIT: Alternatively you could draw the translucent background colour for the child components directly onto the panel, then you would not have to override components:
class YourPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g.create();
// Draw your background image here to g2d.
g2d.setColor(new Color(255, 0, 0, 64));
Area area = new Area();
for (Component component : getComponents()) {
area.add(new Area(component.getBounds()));
}
g2d.fill(area);
g2d.dispose();
}
}
There is a disadvantage to this approach. If there is a genuinely transparent part of a component (such as a rounded border), then its entire background will be coloured.
Related
Situation
I am currently exploring android development on xamarin and therefor decided to develop a small game.
Within the game, I have an ImageButton to access some menus. For instance the level up screen.
I made some low res image for the image button:
Issue
Now, if I use this in the image button, the image gets scaled up and therefore looks Blurry:
I guess, the reason being is bi-linear image sizing.
The proper implementation for my specific case would be sizing with nearest neighbor, as it preserves the low pixel look:
Question
How would I go about changing this? I have found code for WPF winforms but realized that xamarin has different calls...
class ImageButtonWithHardEdgeExpansion : SomeControl
{
public InterpolationMode InterpolationMode { get; set; }
protected override void OnPaint(PaintEventArgs paintEventArgs)
{
paintEventArgs.Graphics.InterpolationMode = InterpolationMode;
base.OnPaint(paintEventArgs);
}
}
For an intermediate workaround, I can use an external image resizer and store the image in high res... but that defies the purpose for me a little. so I am looking for a more long term solution.
You can use the padding to do this.
Before padding:
After padding:
I am drawing graphs on NSView using standard Cocoa drawing APIs. See image below. There are multiple graphs on the NSView which is in a scrollView. Each graph has around 1440 data points and scrolling performance struggles a bit because of redrawing that is being done.
Is there any way to ensure the graphics are only drawn once such that the image can be scrolled up and down smoothly ?
This same view is used to generate a PDF output file.
Given the drawing does not actually need to change unless the view is resized, and this does not happen, is there any way to prevent the view from redrawing itself during scrolling. Hopefully there is a simple switch to ensure the view draw itself once and keeps that in memory!?
The basic code is in the NSView subclass draw() function.
override func draw(_ dirtyRect: NSRect) {
drawAxis()
// Only draw the graph axis during live resize
if self.inLiveResize {
return
}
plot1()
plot2()
plot3()
...
}
func plot1(){
for value in plot1Data {
path = NSBezierPath()
if isFirst {
path?.move(to: value)
} else {
path?.line(to: value)
}
}
}
Apple has pretty comprehensive advice in their View Programming Guide: Optimizing View Drawing article.
It doesn't appear that you're taking even the minimal steps to avoid drawing what you don't have to. For example, what code you've shown doesn't check the dirtyRect to see if a given plot falls entirely outside of it and therefore doesn't need to be drawn.
As described in that article, though, you can often do even better using the getRectsBeingDrawn(_:count:) and/or needsToDraw(_:) methods.
The scroll view can, under some circumstances, save what's already been drawn so your view doesn't need to redraw it. See the release notes for Responsive Scrolling. One requirement of this, though, is that your view needs to be opaque. It needs to override isOpaque to return true. It's not enough to just claim to be opaque, though. Your view actually has to be opaque by drawing the entirety of the dirty rect on every call to draw(). You can fill the dirty rect with a background color before doing other drawing to satisfy this requirement.
Be sure the clip view's copiesOnScroll property is set to true, too. This can be done in IB (although it's presented as an attribute of the scroll view, there) or in code. It should be true by default.
Note that the overdraw that's part of Responsive Scrolling will happen incrementally during idle time. That will involve repeated calls to your view's draw() method. If you haven't optimized that to only draw the things that intersect with the dirty rect(s), then those calls are going to be slow/expensive. So, be sure to do that optimization.
I need to know, which is the best way to blur the background of the Windows Phone 7 app to concentrate the user's attention on a "always on top" popup window.
My idea is:
Make an in-memory screenshot of the background grid (by turning it into a freezable or something).
Add an image that overlaps the background grid, but is below (with the z-index) the popup.
Still I doubt I will be able to overlap the application bar.
At this point, if you have a solution, please advise.
A few pointers for you ...
Unfortunately the Silverlight BlurEffect and other Bitmap effects didn't make it into Window Phone 7, so you will have to implement the blur yourself. This is actually pretty simple, just use a Gaussian Convolution Filter.
To achieve this effect you can capture the visuals of your application into a WriteableBitmap, manipulate the image to create your blur, then overlay this image over your application using a PopUp. I did something similar in a blog post I wrote about fly-out text animations here:
http://www.scottlogic.co.uk/blog/colin/2011/04/metro-in-motion-3-flying-titles/
Find your root visual as follows:
var rootElement = Application.Current.RootVisual as FrameworkElement;
Add a copy of this UI into a popup as follows:
_backgroundMask = new Rectangle()
{
Fill = new SolidColorBrush(Colors.Black),
Opacity = 0.0,
Width = rootElement.ActualWidth,
Height = rootElement.ActualHeight
};
_popupCanvas.Children.Add(_backgroundMask);
_targetElementClone = new Image()
{
Source = new WriteableBitmap(element, null)
};
_popupCanvas.Children.Add(_targetElementClone);
And show it:
_popup.IsOpen = true;
I'll leave you to work out how to blur the background!
As an aside, your will not be able to overlay or capture the application bar visuals. Hide it before performing this transformation.
Finally, blurring the background isn't really very 'Metro'. Are you sure you want to do this?
Instead of blurring just use a semi transparent layer over the top of the page.
You should hide the application bar before trying to create such an effect as you won't be able to place anything on top of it.
I need to draw, move, change shapes (rectangles, circles an so one) on canvas (represented by standard "Static Control"). All drawing operations are realized by standard GDI functions.
I've realized it like this:
(example for moving shape, other operations use the same principle)
...
// Before any actions set foreground mix mode:
SetROP2(hdc_, R2_NOTXORPEN);
...
void OnMouseDown(...)
{
SelectShapeUnderCursor();
}
void OnMouseMove(...)
{
...
DrawShape(old_points); // Eraise shape at old position (drawing with the same pen's color, see description of R2_NOTXORPEN mode)
DrawShape(new_points); // Draw shape at new position
...
}
void OnMouseUp(...)
{
DrawShape(new_points); // Final draw shape
}
In this case shapes correctly moving and changing. But great problem is bad colors of shapes. For example, when pen has green color, shape has green color on white background and red on black background. It's normal behavior for R2_NOTXORPEN mix mode.
But I want to shapes have same color as pen. I must refuse of R2_NOTXORPEN mix mode, but how to correctly realize operations like moving, changing shapes? I may use GDI+, if needed.
This is the way it was done back in the Windows 3.x days when all you had was a 386SUX. Now you just update the internal shape list and call InvalidateRect to let the WM_PAINT message handler re-render all shapes. No need for XOR tricks and its fugly side-effects. Double-buffer when it starts to flicker.
I have a very simple application that has one screen and one button. The main screen has a verticalFieldManager with a BitmapField inside it, and one button beneath the bitmap. I want to be able to overlay another image on top of this when the user clicks a button. The overlay image is a PNG with transparent background, and this is important for design, so I can't use popupscreen or a new screen because the backgrounds are always white by default, and I've heard alpha doesn't really do the trick.
I guess what I'm asking is if anyone knows a simple way to...
A) take a standard verticalFieldManager and overlay a PNG on top of the inner contents
B) overlay a PNG over the screen, no matter the contents
The basic functionality of this app was intended to be - show an image. on click, show another overlaid on top. on click again, remove the popup image.
I haven't found anything that addresses something like this online, but I have read of people doing similar things that utilize popupscreen and new screens in a way I don't need to do.
Hopefully this makes sense.
Thanks
Have you tried something like this in your custom class that overrides a screen?
EncodedImage _overlayImage;
boolean _overlay = false;
// this is to catch the click, you might do it different
public void fieldChanged(Field field, int context)
{
if (field == _imgChangeButton) {
// get the overlay image here, however you want
_overlayImage = getEncodedImageResource(blah);
_overlay = true;
invalidate();
}
}
protected void paint(Graphics graphics) {
super.paint(graphics);
if (_overlay) {
graphics.drawImage(...);
}
}
If the PNG has transparency in it the bb drawImage stuff should deal with it ok. In the drawImage call obviously you can mess around with finding the existing image and setting the x,y right on top of it.
In general I would say do a lot of testing with paint() and messing with the graphics directly before you try to do anything with another screen. You can do a lot overriding paint() for the screen... you get the whole graphics.