Port from direct draw to layout??

Hi all, I'm trying to por mi new simple app writen directly doing

dc.drawText(60, 180, Graphics.FONT_NUMBER_MILD, string_temperatura, Graphics.TEXT_JUSTIFY_CENTER);

to

findDrawableById("temperaturaLabel").setText(string_temperatura.toString());

and after a lot of reading now this part seems to work fine.

The new challenge its to put behing the this text some graphical elemente like a rectangle o circle.  I dont know how can I do or I'm missunderstanting something.

Part of my code...

function onLayout(dc){
    setLayout(Rez.Layouts.Principal(dc));
}

function onUpdate(dc) {
    View.onUpdate(dc);

    dc.setColor(Graphics.COLOR_LT_GRAY, Graphics.COLOR_TRANSPARENT);
    dc.fillRectangle(122, 104, 240, 15);
    //Zona0.draw(dc);

    //var Zona0 = findDrawableById("Zona0");
    //Zona0[0].setColor(0xAAFF55); 

    //HR
    findDrawableById("HRLabel").setText(string_HR.toString());
    //dc.drawText(180, 50, Graphics.FONT_NUMBER_THAI_HOT, string_HR, Graphics.TEXT_JUSTIFY_CENTER);
}

when I draw the rectangle it puts over the text of hr and I want to put it behind.

Any help will be appreciated

Thanks

  • The problem is that you are mixing layouts and direct drawing operations. This can be done, but you have to know what you are doing.

    Objects can be drawn directly via dc.drawXXX() or indirectly via a Drawable. When you call View.onUpdate(dc), you are asking the base View class to draw the layout (an array of Drawables) that you specified in a previous call to View.setLayout(). When drawing, it is important to understand that later draws happen on top of earlier draws.

    In your code above, the call to View.onUpdate(dc) tells the base View to draw all of the drawable elements in the layout (including the HRLabel). After they have been drawn you are drawing a gray rectangle. As I mentioned earlier, this later draw is going to be done on top of the earlier draws, potentially obscuring something that was drawn by the layout. After you've drawn the rectangle, you are updating the text of the label. This itself is fine, but it isn't good because the new value won't be displayed until the next time the view is refreshed.

    To do what you want, you should update the label text before you update the view (so the value displayed is the most recent) and you'll probably want to use a Drawable for the grey rectangle and put that drawable into the layout.

  • I would probably just stick with using direct dc for everything, as using a layout can not only confuse things, but take a bit more memory.

    clear screen

    dc.drawRectangle

    dc.drawText for temperature

    If the x,y,etc is an issue because they are hard coded, you can use class variables and set those in onLayout, wher you can use things like dc.getWidth/dc.getHeight and mayvbe a dc.getFontHeight to set the x and y, width and height of things..

  • Hi Travis, thanks for your answer.

    I think I understand what you say.

    At the beginning I put the View.onUpdate(dc) behind but in this case all direct draws of my rectangles desappeared (it never showed) but the layout was ok with the different layouts for different devices that I coded.

    I dont know how can I draw behind the layout that I thinks its basically what I want, but can be I'm confused how it works.

    I want to draw this rectangles behind the hr value like a vumeter and cant be fixed.

    Thanks for your help.

  • Hi jim, thanks for your answer.

    now all my code it's harcoded and when I saw for the layout I thought it can be a good idea to port and at the beginning was fine because I only focused on the data fields.  The problem was with the different drawing concepts that I have in my mind to use.  I dont know how can put it on to works how I spected.

    I dont know if they are more sdk documents or I need to continue testing things.

    Thanks for your help.

  • Thanks both, I find a good solution.

    I assign into an array the layout and I can use it to draw every element with draw(dc) respecting the coordenates.

    In this way I can put on every kind of devide the element on I want.

    Thanks for your light.

  • Keep in mind that when you use a layout, it's actually doing direct draws "under the hood".

    Consider this code.  It draws the time in the center of the screen with a rectangle around it, and it works on any device:

    using Toybox.WatchUi;
    using Toybox.Graphics;
    using Toybox.System;
    using Toybox.Lang;
    
    class swfView extends WatchUi.WatchFace {
    	var width,height,recX,recY,recW,recH,font=Graphics.FONT_LARGE;
    
        function initialize() {
            WatchFace.initialize();
        }
    
        function onLayout(dc) {
    		width=dc.getWidth();
    		height=dc.getHeight();
    		var fH=dc.getFontHeight(font);
    		recY=height/2-fH*.6;
    		recW=dc.getTextWidthInPixels("23:88", font)+10;
    		recX=width/2-recW/2;
    		recH=fH*1.2;
        }
    
        function onUpdate(dc) {
            var clockTime = System.getClockTime();
            var timeString = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);
    
    		dc.setColor(Graphics.COLOR_BLACK,Graphics.COLOR_BLACK);
    		dc.clear();
    		dc.setColor(Graphics.COLOR_YELLOW,Graphics.COLOR_TRANSPARENT);
    		dc.drawRectangle(recX, recY, recW, recH);
    		dc.setColor(Graphics.COLOR_PINK,Graphics.COLOR_TRANSPARENT);
    		dc.drawText(width/2,height/2,font,timeString,Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
        }
    }

    This is what I mean by not hard coding things like x/y/width/height

    Here's a venu:

    and an f5+

    if you want to keep using layouts, you may want to look at using relative layouts.  See https://forums.garmin.com/developer/connect-iq/b/news-announcements/posts/using-relative-layouts-and-textarea

    "As you can see, it’s become much easier to display messages to your users. The goal is to allow developers to be able to handle almost all devices with the same layout."

  • Thanks for all jim.  I'll use your code in my projects for sure!! thanks.

  • I dont know how can I draw behind the layout that I thinks its basically what I want, but can be I'm confused how it works.

    You can't draw behind the layout if you're calling View.onUpdate(dc) because the base View clears the screen and then draws each of the drawables in the layout.


  • Finally I delete de View.onUpdate(dc) and retype part of my code and now works like I spected.

    In onLayout function..

    function onLayout(dc){
            screenWidth = dc.getWidth();
            screenHeight = dc.getHeight();
            mLayout = Rez.Layouts.Principal(dc);
              return true;          
        }

    and after this i can use mLayout on I whant onUpdate function like this...

    function onUpdate(dc) {
                    //Dibujamos el fondo
                    mLayout[0].draw(dc);
    
    //HR
                    campo = mLayout[5];
                    campo.setText(string_HR.toString());
                    campo.draw(dc);
    
    }

    and if I need to change someting not drawing directly like a font

    //Texto HR
                    campo = mLayout[10];
                    campo.setFont(fuente1);
                    campo.setText("BPM");
                    campo.draw(dc);
    
    
    

    Doing this, I can use a layout by device and positioning every data in place.

    Thanks to both for your help.