{"id":2592,"date":"2018-01-23T15:23:33","date_gmt":"2018-01-23T14:23:33","guid":{"rendered":"https:\/\/www.vikingsoftware.com\/uncategorized-da\/creating-custom-widgets\/"},"modified":"2018-01-23T15:23:33","modified_gmt":"2018-01-23T14:23:33","slug":"creating-custom-widgets","status":"publish","type":"post","link":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/","title":{"rendered":"Creating custom widgets"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"2592\" class=\"elementor elementor-2592 elementor-643\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-section elementor-top-section elementor-element elementor-element-50cb995 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"50cb995\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-902978e\" data-id=\"902978e\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c3830ab elementor-widget elementor-widget-text-editor\" data-id=\"c3830ab\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<pre><strong>Written by Bo Thorsen<\/strong><br \/><strong>2018\/01\/23<\/strong><\/pre>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ed2663a elementor-widget elementor-widget-menu-anchor\" data-id=\"ed2663a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"top\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3f53cdf elementor-widget elementor-widget-text-editor\" data-id=\"3f53cdf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Navigation<\/h2>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-375fd78 elementor-align-start elementor-icon-list--layout-traditional elementor-list-item-link-full_width elementor-widget elementor-widget-icon-list\" data-id=\"375fd78\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-list.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul class=\"elementor-icon-list-items\">\n\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#sizing\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Sizing for layouts \/ size policy<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#focus\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Focus policy<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#painting\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Painting<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#qstyle\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">QStyle support<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#input\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Input handling<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#properties\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Properties<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#signals\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Signals and slots<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#designer\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Designer plugin<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"#final\">\n\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Final thoughts<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4b429f9 elementor-widget elementor-widget-text-editor\" data-id=\"4b429f9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Creating custom widgets is not a hard problem, but there are a few things you should consider. Here I present a simple list of what you should at least consider doing. I won\u2019t handle the case where you build a widget that is just a container with children, because this is not a \u201creal\u201d custom widget. This is about creating a completely new widget that is not included in the standard list of widgets.&nbsp;<\/p>\n<p>This blog is meant as a check-list you can go to, when you create a new widget. Just run through the items below and you are well on your way to creating a good widget that will serve you well in many different circumstances. What you won\u2019t see here is a deep and thorough discussion of how to do each of them. But I will give you a bunch of hints and tips on how to do a properly good job when you are tasked with creating a custom widget.<\/p>\n<p>The list of things you need to consider are the following:<\/p>\n<ul>\n<li>Sizing for layouts<\/li>\n<li>Size policy<\/li>\n<li>Focus policy<\/li>\n<li>Painting<\/li>\n<li>QStyle support<\/li>\n<li>Input handling<\/li>\n<li>Properties<\/li>\n<li>Signals and slots<\/li>\n<li>Designer plugin<\/li>\n<\/ul>\n<p>This is perhaps a surprisingly long list. And there will be some of those you won\u2019t need to handle.<\/p>\n<p>If you don\u2019t have a lot of experience with creating custom widgets, you should go through the items below methodically. As you gain experience, this simple list will be enough. And, of course, later you won\u2019t need it at all.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<section data-particle_enable=\"false\" data-particle-mobile-disabled=\"false\" class=\"elementor-section elementor-inner-section elementor-element elementor-element-60c64c9 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"60c64c9\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t\t<div class=\"elementor-background-overlay\"><\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-inner-column elementor-element elementor-element-5f8227e\" data-id=\"5f8227e\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-a1fa396 elementor-widget elementor-widget-text-editor\" data-id=\"a1fa396\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2>Download Check-List<\/h2>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a2d0898 elementor-widget elementor-widget-text-editor\" data-id=\"a2d0898\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Make custom widget development easier for yourself by saving this check-list and using it whenever you start a new widget.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-49d4849 elementor-align-center elementor-widget elementor-widget-button\" data-id=\"49d4849\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-button-wrapper\">\n\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"https:\/\/www.vikingsoftware.com\/wp-content\/uploads\/2021\/10\/Creating-custom-widgets-list.pdf\" target=\"_blank\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Click here to download<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<div class=\"elementor-element elementor-element-1cb7aa2 elementor-widget elementor-widget-menu-anchor\" data-id=\"1cb7aa2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"sizing\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cffec43 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"cffec43\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-da0ab7e elementor-widget elementor-widget-text-editor\" data-id=\"da0ab7e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Sizing for layouts \/ size policy<\/strong><\/h2><p>One of the things you should always do is handle sizing. This is not needed, if you don\u2019t use layout managers, because then the sizing of this widget will be handled from the outside. But in my almost 21 years as a Qt developer, I have so far not seen a single case where it was a good idea not to use the layouts.<\/p><p>The one thing you must do is to give it a size hint. Just override the sizeHint() method and return the proper size for this widget. The trick is to figure out what the proper size is. In some cases this will rely on font size, or the contents. In those cases, you need to notify the layout system that the size hint has changed, if the content or font changes. You do this by calling updateGeometry().<\/p><p>For a few widgets, the height depends on how wide the widget is set, or the width depends on the height. In these cases, override the heightForWidth or widthForHeight methods. Those are pretty rare, though.<\/p><p>It is the size policy that tells the layout managers how to use the size information from the widget. These size policies are the one thing that most other window layout systems miss, and it\u2019s the key to fully using the Qt systems power. You need to set those correctly. In an upcoming blog entry, I will go into detail about the layouts and the size policies, so I will only briefly mention those here. In most cases you simply call setSizePolicy() with the policies for vertical and horizontal. These can be overwritten by the users of this widget class, but it\u2019s important that you set reasonable defaults. Find the proper size policies in\u00a0<a href=\"http:\/\/doc.qt.io\/qt-5\/qsizepolicy.html#Policy-enum\">the documentation<\/a>. It\u2019s a good tip to look at the value, because the flags are to me a very good hint at what the size policies really do \u2013 in many cases better than the description text. Finally, remember that many widgets have different size policies for vertical and horizontal.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bdfacca elementor-widget elementor-widget-menu-anchor\" data-id=\"bdfacca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"focus\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dad72c9 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"dad72c9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1e64e51 elementor-widget elementor-widget-text-editor\" data-id=\"1e64e51\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Focus policy<\/strong><\/h2><p>The focus policy is quite simple, as it\u2019s only about keyboard input. There are basically only two that makes sense: No focus or strong focus.<\/p><p>Once you have focus, the keyboard events will go to this widget.<\/p><p>Note that you can get keyboard events even if this has a no focus policy, if the widget has children with focus, who doesn\u2019t accept the keyboard events. But this is admittedly a rare thing to do. Usually, if you set no focus, then you don\u2019t add keyboard handlers.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8d80421 elementor-widget elementor-widget-menu-anchor\" data-id=\"8d80421\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"painting\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e46e526 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"e46e526\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b93aa0f elementor-widget elementor-widget-text-editor\" data-id=\"b93aa0f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Painting<\/strong><\/h2><p>Unless you are creating an invisible container widget, you are of course going to need some painting. Implement the paintEvent() method. This is only mentioned for completeness, and I won\u2019t go into details with it.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5746e52 elementor-widget elementor-widget-menu-anchor\" data-id=\"5746e52\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"painting\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cdf5f3e elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"cdf5f3e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c95f8ed elementor-widget elementor-widget-text-editor\" data-id=\"c95f8ed\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>QStyle support<\/strong><\/h2><p>There are basically two things you need to do on the widget side, if you\u2019re using a QStyle. Those are to implement the size hint and paint event by just calling the style.<\/p><p>In both cases, you need a style option. Initialize that and call the proper method on the current style. I usually create a private method on the d-pointer that sets up the fields of the style option. Remember that the base QStyleOption has an initFrom() method that sets up the standard QWidget fields.<\/p><p>Sometimes you create a custom widget that looks to the user like it\u2019s a standard Qt widget \u2013 a QComboBox like widget, for example. The reason for doing this is to modify the default behaviour in a way you can\u2019t do with the available API on the widget. In this case, you can reuse the styling code to handle size and painting by calling the style with the proper option object. And then you implement the input handlers to change the widget behaviour.<\/p><p>However, in most cases, the custom widgets require custom style code. The way to do this is usually to inherit QProxyStyle and add the code to handle your widget(s) here and call the standard code for all other widgets.<\/p><p>It\u2019s not a clear cut decision whether or not to support styles in custom widgets. In some cases, the sizes and painting are going to be the same no matter what the system style is, and in that case it makes no sense at all to move the size and paint code to the style. But if you do have to implement different styles for your widget, then you should go with the style code.<\/p><p>It\u2019s also a decision that can quite easily be changed later, as the code is fairly similar, whether or not it\u2019s placed in the class itself or in a style class.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e480ba6 elementor-widget elementor-widget-menu-anchor\" data-id=\"e480ba6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"input\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9a904e7 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"9a904e7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-049966e elementor-widget elementor-widget-text-editor\" data-id=\"049966e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Input handling<\/strong><\/h2><p>There are a lot of input types in Qt:<\/p><ul><li>Keyboard<\/li><li>Mouse<\/li><li>Mouse wheel<\/li><li>Touch screens<\/li><li>Pen tablets (Wacom boards for example)<\/li><li>Custom hardware for non standard input<\/li><\/ul><p>All of those can have an effect on your widget, if you want them to. The most common thing is to implement just the keyboard and mouse, because for most widgets the standard conversion from touch or pen tablet to mouse is fine. But if you need the additional information from the pen strength\/size etc or have to handle multi touch, then you need to implement support for these as well.<\/p><p>A lot of custom hardware is usually mapped to actually work with keyboard events, which saves you from handling those in some weird fashion. If this is the case, you can see the key codes that you receive from the hardware and react to those.<\/p><p>Handling keyboard is important even for widgets that doesn\u2019t allow text input. For example, a button will normally allow space or enter to work as a mouse press, and radio buttons will allow keys up or down to switch the current setting. The key (no pun intended) is to try and help the user by allowing him or her to do what feels natural.<\/p><p>You also need to remember that input handling adds states that the painting (or the size) needs to handle. For example, a normal button has these flags that can be true or not: Pressed, focus, enabled and mouse hover. Combining those leads to a bunch of independent states that all need to be drawn differently. (None of those will affect the size of a button, but setting the text on it will.)<\/p><p>When you get a specification from a graphics artist on how the widget should look, one of the first things you need to do is to sit down and go through the widget states and make sure they are all covered by the spec. Because they never are. So you need a round trip to the graphics people to get a complete spec, and you might as well do the rest of the code while you wait for the updated spec.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f9e8b78 elementor-widget elementor-widget-menu-anchor\" data-id=\"f9e8b78\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"properties\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f0b825d elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"f0b825d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-00d47f9 elementor-widget elementor-widget-text-editor\" data-id=\"00d47f9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Properties<\/strong><\/h2><p>The Qt properties serve a number of purposes:<\/p><ul><li>Tell the widget users what the properties that modify widget contents are.<\/li><li>Export the property to QML code. Sure, you can\u2019t just show a QWidget in QML, but they are also QObjects where you can manipulate the properties. It\u2019s not a good reason in this particular blog entry, but normally it is.<\/li><li>If you implement a designer plugin, the properties are available for manipulation in designer for this widget.<\/li><li>Works with Qt introspection so you can list the properties and manipulate them dynamically (which is what designer does).<\/li><\/ul><p>Of those, the first is\u00a0<em>always<\/em>\u00a0valid. And for this reason I tend to use Q_PROPERTY for all properties on my object classes. You should at least make the value(s) of the widget a property, but there might be others as well \u2013 headers, suffix, etc.<\/p><p>The only thing special (when speaking about code) to widgets about properties is if you add a designer plugin. In all other aspects, the properties have the same advantages as for any QObject subclass.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3184f4d elementor-widget elementor-widget-menu-anchor\" data-id=\"3184f4d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"signals\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1b9391b elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"1b9391b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3af3c07 elementor-widget elementor-widget-text-editor\" data-id=\"3af3c07\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Signals and slots<\/strong><\/h2><p>Proper use of signals and slots is one of my biggest pet peeves in Qt development. If you watched my QObject Deep Dive at the Qt World Summit 2017, you will know this is an area I care a lot about.<\/p><p>To me, signals and slots are one of the ways you can help yourself avoid the dreaded spaghetti code. This is done by creating black boxes that do not know anything about the outside world. The Qt signal\/slot system is just an implementation of the visitor pattern, where some of the work is automatically done for you.<\/p><p>For example, the button knows whether or not it\u2019s been clicked. It will tell you when it\u2019s clicked by emitting a signal. And it has no clue about what the consequence of a click is. Most developers instantly see that it\u2019s wrong for the button to handle a click directly, by calling some function when it happens. But the same developers do not follow this for other widgets, so suddenly the changes in widget state results in a direct call somewhere.<\/p><p>The proper way to think about signals and slots is that it\u2019s the API for setting and listening to an object. And two objects are connected from signal to slot by a third object that owns both of them. That owner object is the one that knows what the consequence of, for example, the click is.<\/p><p>When you consider which slots to offer, it\u2019s mostly simple setter methods, when we\u2019re talking widgets. Another usual type is to perform the action of the widget \u2013 click the button or trigger the action. For controller objects it\u2019s not this simple, because there are a lot of slots that are connected to the action signals from the widgets. But for widgets it\u2019s often the case that our slots are setters or actions. Most properties will have a slot, unless they are read only. There are also some methods you allow to be slots, simply because you connect them to other objects, but again this isn\u2019t common for widgets. Except in the case where a widget has children, and in that case you usually use private slots or lambda slots to connect to the children signals.<\/p><p>For signals, you should communicate changes in states for your widget. It\u2019s not all states that should be emitted as signals, for example a press by a mouse isn\u2019t communicated, the release isn\u2019t, but the aggregated event \u201cclicked\u201d is. You should also add a myPropertyChanged signal for each property.<\/p><p>For a longer discussion of this topic, you can\u00a0<a href=\"https:\/\/www.youtube.com\/watch?v=hksm8IRU3fk\">watch the video with my talk from Qt WS 2017<\/a>.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-73e9142 elementor-widget elementor-widget-menu-anchor\" data-id=\"73e9142\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"designer\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-601e4c5 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"601e4c5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-34820e1 elementor-widget elementor-widget-text-editor\" data-id=\"34820e1\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Designer plugin<\/strong><\/h2>\n<p>The purpose of a designer plugin is to allow the UI\/UX people and the developers to manipulate your custom widgets in Qt designer. Or in the embedded designer in Qt Creator.<\/p>\n<p>When you install the plugin, you get your widget in the list of available widgets, and all the custom properties are available to set up. Also, the widget will be properly painted by the actual paint event in your widget. And you can also make it look like the proper QStyle, if you have a custom style as well.<\/p>\n<p>The alternative to doing this is to use the designer promotion, where you just tell designer that you have a widget and it\u2019s a subclass of QWidget (or QFrame, or whatever you actually have). In this case you only see the base class properties. You can in theory set the properties with dynamic properties, but please don\u2019t. In this case, set up your custom widget in code where it is created.<\/p>\n<p>Creating a designer often seems like a good idea. However, it does present you with some deployment problems, especially for large teams. Because you almost force the entire set of developers to build and install the plugin before they can use the designer. It\u2019s not necessary for compilation, though, it\u2019s only if you do any work in designer itself that you need it. Unfortunately designer plugins are notoriously difficult to compile, and I have seen endless questions about the plugins from the teams we have worked with. The problem is that you have to build it with exactly the same compiler tool chain as designer was built with, and you have to do it in release mode. Unless your Qt is built in debug, then your plugin needs to be built in debug mode as well. So you can\u2019t just always use the same compiler as you build the application with, if you use the system Qt or a downloaded Qt version. It\u2019s easier, though, if all developers work with a custom built Qt. But these days it\u2019s rare to see that.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-01130d0 elementor-widget elementor-widget-menu-anchor\" data-id=\"01130d0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"menu-anchor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-menu-anchor\" id=\"final\"><\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5ad7465 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"5ad7465\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<a class=\"elementor-icon\" href=\"#top\">\n\t\t\t<i aria-hidden=\"true\" class=\"fas fa-angle-double-up\"><\/i>\t\t\t<\/a>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-be676ef elementor-widget elementor-widget-text-editor\" data-id=\"be676ef\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h2><strong>Final thoughts<\/strong><\/h2><p>I haven\u2019t mentioned QML items here, since it\u2019s about widgets. But I actually apply a lot of the same rules when creating custom items. I always have a top level Item that encapsulates the item contents. On the top level item I place the public properties, signals and functions. And I handle size, painting, input events etc. Most of the things in the list are valid for QML as well, although you have to map the concept to how QML works.<\/p><p>I\u2019ll leave you with one final tip: Don\u2019t place any logic in the widget, other than the logic necessary for the widget itself (paint states, input handling\u2026). Logic that handles anything outside of the widget states needs to go somewhere else. Emit signals and react to those outside of the widget instead.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Creating custom widget is not a hard problem, but there are a few things you should consider. Here I present\u00a0a simple list of what you should at least consider doing<\/p>\n","protected":false},"author":4,"featured_media":1924,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[94],"tags":[96,95,99],"class_list":["post-2592","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-da","tag-cplusplus-da","tag-qt-da","tag-widgets-da"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Creating custom widgets - Viking Software A\/S<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/\" \/>\n<meta property=\"og:locale\" content=\"da_DK\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Creating custom widgets - Viking Software A\/S\" \/>\n<meta property=\"og:description\" content=\"Creating custom widget is not a hard problem, but there are a few things you should consider. Here I present\u00a0a simple list of what you should at least consider doing\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/\" \/>\n<meta property=\"og:site_name\" content=\"Viking Software A\/S\" \/>\n<meta property=\"article:published_time\" content=\"2018-01-23T14:23:33+00:00\" \/>\n<meta name=\"author\" content=\"Maria Lisberg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Skrevet af\" \/>\n\t<meta name=\"twitter:data1\" content=\"Maria Lisberg\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimeret l\u00e6setid\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutter\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/\"},\"author\":{\"name\":\"Maria Lisberg\",\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/#\\\/schema\\\/person\\\/9b67e226302628047186fd9359931e56\"},\"headline\":\"Creating custom widgets\",\"datePublished\":\"2018-01-23T14:23:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/\"},\"wordCount\":2593,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.vikingsoftware.com\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Widgets-e1622460876593.png\",\"keywords\":[\"C++\",\"Qt\",\"Widgets\"],\"articleSection\":[\"Blog\"],\"inLanguage\":\"da-DK\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/\",\"url\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/\",\"name\":\"Creating custom widgets - Viking Software A\\\/S\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.vikingsoftware.com\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Widgets-e1622460876593.png\",\"datePublished\":\"2018-01-23T14:23:33+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/#\\\/schema\\\/person\\\/9b67e226302628047186fd9359931e56\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#breadcrumb\"},\"inLanguage\":\"da-DK\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"da-DK\",\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.vikingsoftware.com\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Widgets-e1622460876593.png\",\"contentUrl\":\"https:\\\/\\\/www.vikingsoftware.com\\\/wp-content\\\/uploads\\\/2018\\\/01\\\/Widgets-e1622460876593.png\",\"width\":1400,\"height\":564},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/blog-da\\\/creating-custom-widgets\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Creating custom widgets\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/#website\",\"url\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/\",\"name\":\"Viking Software A\\\/S\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"da-DK\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.vikingsoftware.com\\\/da\\\/#\\\/schema\\\/person\\\/9b67e226302628047186fd9359931e56\",\"name\":\"Maria Lisberg\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"da-DK\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b8b13978f2a67726c7f50acfc73600aa7902481eec9fb6673919cfaf3db353b8?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b8b13978f2a67726c7f50acfc73600aa7902481eec9fb6673919cfaf3db353b8?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b8b13978f2a67726c7f50acfc73600aa7902481eec9fb6673919cfaf3db353b8?s=96&d=mm&r=g\",\"caption\":\"Maria Lisberg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Creating custom widgets - Viking Software A\/S","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/","og_locale":"da_DK","og_type":"article","og_title":"Creating custom widgets - Viking Software A\/S","og_description":"Creating custom widget is not a hard problem, but there are a few things you should consider. Here I present\u00a0a simple list of what you should at least consider doing","og_url":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/","og_site_name":"Viking Software A\/S","article_published_time":"2018-01-23T14:23:33+00:00","author":"Maria Lisberg","twitter_card":"summary_large_image","twitter_misc":{"Skrevet af":"Maria Lisberg","Estimeret l\u00e6setid":"13 minutter"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#article","isPartOf":{"@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/"},"author":{"name":"Maria Lisberg","@id":"https:\/\/www.vikingsoftware.com\/da\/#\/schema\/person\/9b67e226302628047186fd9359931e56"},"headline":"Creating custom widgets","datePublished":"2018-01-23T14:23:33+00:00","mainEntityOfPage":{"@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/"},"wordCount":2593,"commentCount":0,"image":{"@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#primaryimage"},"thumbnailUrl":"https:\/\/www.vikingsoftware.com\/wp-content\/uploads\/2018\/01\/Widgets-e1622460876593.png","keywords":["C++","Qt","Widgets"],"articleSection":["Blog"],"inLanguage":"da-DK","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/","url":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/","name":"Creating custom widgets - Viking Software A\/S","isPartOf":{"@id":"https:\/\/www.vikingsoftware.com\/da\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#primaryimage"},"image":{"@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#primaryimage"},"thumbnailUrl":"https:\/\/www.vikingsoftware.com\/wp-content\/uploads\/2018\/01\/Widgets-e1622460876593.png","datePublished":"2018-01-23T14:23:33+00:00","author":{"@id":"https:\/\/www.vikingsoftware.com\/da\/#\/schema\/person\/9b67e226302628047186fd9359931e56"},"breadcrumb":{"@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#breadcrumb"},"inLanguage":"da-DK","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/"]}]},{"@type":"ImageObject","inLanguage":"da-DK","@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#primaryimage","url":"https:\/\/www.vikingsoftware.com\/wp-content\/uploads\/2018\/01\/Widgets-e1622460876593.png","contentUrl":"https:\/\/www.vikingsoftware.com\/wp-content\/uploads\/2018\/01\/Widgets-e1622460876593.png","width":1400,"height":564},{"@type":"BreadcrumbList","@id":"https:\/\/www.vikingsoftware.com\/da\/blog-da\/creating-custom-widgets\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.vikingsoftware.com\/da\/"},{"@type":"ListItem","position":2,"name":"Creating custom widgets"}]},{"@type":"WebSite","@id":"https:\/\/www.vikingsoftware.com\/da\/#website","url":"https:\/\/www.vikingsoftware.com\/da\/","name":"Viking Software A\/S","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.vikingsoftware.com\/da\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"da-DK"},{"@type":"Person","@id":"https:\/\/www.vikingsoftware.com\/da\/#\/schema\/person\/9b67e226302628047186fd9359931e56","name":"Maria Lisberg","image":{"@type":"ImageObject","inLanguage":"da-DK","@id":"https:\/\/secure.gravatar.com\/avatar\/b8b13978f2a67726c7f50acfc73600aa7902481eec9fb6673919cfaf3db353b8?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/b8b13978f2a67726c7f50acfc73600aa7902481eec9fb6673919cfaf3db353b8?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b8b13978f2a67726c7f50acfc73600aa7902481eec9fb6673919cfaf3db353b8?s=96&d=mm&r=g","caption":"Maria Lisberg"}}]}},"_links":{"self":[{"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/posts\/2592","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/comments?post=2592"}],"version-history":[{"count":0,"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/posts\/2592\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/media\/1924"}],"wp:attachment":[{"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/media?parent=2592"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/categories?post=2592"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vikingsoftware.com\/da\/wp-json\/wp\/v2\/tags?post=2592"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}