Deprecated: Creation of dynamic property GeneralSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Deprecated: Creation of dynamic property AbstractSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Deprecated: Creation of dynamic property UserSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_init_login.inc.php on line 81

Deprecated: Creation of dynamic property CollectionSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/inc/_core/_template.funcs.php on line 467

Deprecated: Creation of dynamic property ItemList2::$filterset_name is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlistlight.class.php on line 114

Deprecated: preg_match(): Passing null to parameter #2 ($subject) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_param.funcs.php on line 1407

Deprecated: preg_match(): Passing null to parameter #2 ($subject) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_param.funcs.php on line 1407

Deprecated: Creation of dynamic property ItemQuery::$dbtablename is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 78

Deprecated: Creation of dynamic property ItemQuery::$dbprefix is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 79

Deprecated: Creation of dynamic property ItemQuery::$dbIDname is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 80

Deprecated: Creation of dynamic property ItemQuery::$Blog is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 231

Deprecated: Creation of dynamic property ItemQuery::$cat_array is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 232

Deprecated: Creation of dynamic property ItemQuery::$cat_modifier is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 233

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: Creation of dynamic property ItemQuery::$assignees_logins is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 525

Deprecated: Creation of dynamic property ItemQuery::$author_assignee is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 557

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: Creation of dynamic property ItemQuery::$m is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 842

Deprecated: Creation of dynamic property ItemQuery::$w is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 843

Deprecated: Creation of dynamic property Item::$objtype is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 164

Deprecated: Creation of dynamic property Item::$datestart is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 175

Deprecated: Creation of dynamic property Item::$objtype is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 164

Deprecated: Creation of dynamic property Item::$datestart is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 175

Deprecated: Creation of dynamic property Item::$objtype is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 164

Deprecated: Creation of dynamic property Item::$datestart is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 175

Deprecated: Creation of dynamic property Item::$objtype is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 164

Deprecated: Creation of dynamic property Item::$datestart is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 175

Deprecated: Creation of dynamic property Item::$objtype is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 164

Deprecated: Creation of dynamic property Item::$datestart is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 175

Deprecated: Creation of dynamic property Item::$objtype is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 164

Deprecated: Creation of dynamic property Item::$datestart is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 175

Deprecated: Creation of dynamic property Item::$objtype is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 164

Deprecated: Creation of dynamic property Item::$datestart is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemlight.class.php on line 175

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/inc/_core/_template.funcs.php on line 40

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/inc/_core/_template.funcs.php on line 405

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/inc/_core/_template.funcs.php on line 406

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/inc/_core/_template.funcs.php on line 407

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/inc/_core/_template.funcs.php on line 408

Deprecated: Creation of dynamic property ItemQuery::$dbtablename is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 78

Deprecated: Creation of dynamic property ItemQuery::$dbprefix is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 79

Deprecated: Creation of dynamic property ItemQuery::$dbIDname is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 80

Deprecated: Creation of dynamic property ItemQuery::$Blog is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 231

Deprecated: Creation of dynamic property ItemQuery::$cat_array is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 232

Deprecated: Creation of dynamic property ItemQuery::$cat_modifier is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 233

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: Creation of dynamic property ItemQuery::$assignees_logins is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 525

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10535

Deprecated: explode(): Passing null to parameter #2 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/_core/_misc.funcs.php on line 10540

Deprecated: Creation of dynamic property ItemQuery::$m is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 842

Deprecated: Creation of dynamic property ItemQuery::$w is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_itemquery.class.php on line 843

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/skins/_rss2/index.main.php on line 45

Warning: Cannot modify header information - headers already sent by (output started at /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php:121) in /home4/tylering/public_html/b2e/skins/_rss2/index.main.php on line 46
Switched Keys - Category: "Computing" https://tylerhosting.com/b2e/dbell.php Switched Keys, the blogs of Dana Bell of Tyler, Texas en-US http://blogs.law.harvard.edu/tech/rss 60 Images in b2evolution https://tylerhosting.com/b2e/dbell.php/images-in-b2evolution Sat, 12 Aug 2017 03:04:00 +0000 Dana Bell Information Technology Site Small Talk Design Computing 394@https://tylerhosting.com/b2e/
Deprecated: Creation of dynamic property Item::$cache_has_content_parts is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 4911

Deprecated: Creation of dynamic property tinymce_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property calendar_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property calendar_plugin::$dbtable is deprecated in /home4/tylering/public_html/b2e/plugins/_calendar.plugin.php on line 53

Deprecated: Creation of dynamic property calendar_plugin::$dbprefix is deprecated in /home4/tylering/public_html/b2e/plugins/_calendar.plugin.php on line 54

Deprecated: Creation of dynamic property calendar_plugin::$dbIDname is deprecated in /home4/tylering/public_html/b2e/plugins/_calendar.plugin.php on line 55

Deprecated: Creation of dynamic property quicktags_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property auto_anchors_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property shortlinks_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property custom_tags_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property archives_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property archives_plugin::$dbtable is deprecated in /home4/tylering/public_html/b2e/plugins/_archives.plugin.php on line 54

Deprecated: Creation of dynamic property archives_plugin::$dbprefix is deprecated in /home4/tylering/public_html/b2e/plugins/_archives.plugin.php on line 55

Deprecated: Creation of dynamic property archives_plugin::$dbIDname is deprecated in /home4/tylering/public_html/b2e/plugins/_archives.plugin.php on line 56

Deprecated: Creation of dynamic property email_elements_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property financial_contribution_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property inlines_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property ping_b2evonet_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property ping_pingomatic_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property twitter_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property webmention_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property webmention_plugin::$ping_service_process_message is deprecated in /home4/tylering/public_html/b2e/plugins/webmention_plugin/_webmention.plugin.php on line 52

Deprecated: Creation of dynamic property webmention_plugin::$ping_service_setting_title is deprecated in /home4/tylering/public_html/b2e/plugins/webmention_plugin/_webmention.plugin.php on line 53

Deprecated: Creation of dynamic property autolinks_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property videoplug_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property auto_p_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property mermaid_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property texturize_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property nofollow_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property content_blocks_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property table_contents_plugin::$classfile_path is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_plugins.class.php on line 413

Deprecated: Creation of dynamic property Item::$renderers_validated is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 11107

Deprecated: Creation of dynamic property Item::$pages is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 2412

Deprecated: Creation of dynamic property ItemSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121
<p>Many years ago I started using <a href="http://b2evolution.net/">b2evolution</a> for my blog even though it was not the most popular platform. I'm still using it. Although it is complex, it gives me options that don't exist in other platforms. Now that it has expanded to include other types of collections (photo blogs, manuals, etc), it is even more complex. Unfortunately, the image insertion routines in b2evolution are quite inflexible, and I suspect that is one reason it will never be very popular.</p> <p>The guide says you should attach the image where you want it, but it doesn't include the file in the page markup and instead includes a tag that identifies the image. The logic presented in the on-line forums is that you can adjust the stylesheet and php to apply uniformly to all images. You can put the image in different sections (teaser, cover, in-line) of the post and it supposedly is more efficient that way.</p> <h3>The Issue</h3> <p>Although you have multiple options for placement (vertically) in a post, if it's an in-line image you can't see it in the editor. Instead you see . Additionally you can't modify the formatting of the image. That's where the problems resides. If b2evolution included the code in-line (like it used to) I could modify the HTML/CSS to format the image. </p> <p>Emulating a print publication, I like to wrap text around some images, and like adjusting the size to make it look more balanced. Well, there is a way to include the markup, but it's not intuitive.</p> <h3>The Work Around</h3> <p>I've discovered after inserting all my images that there is a viable workaround to get the code into the post, something that used to be an option in the editor in past versions.</p> <p>1. Go to the b2e Back-office and select Files &gt; Browse and upload the images for the post. I prefer to put them in the root collection folder, not the quick-uploads.<br /> <br />2. From the post, attach any image to the post (ideally an inline). The easiest way is to select Attach existing files and select one. You won't be including that in the post, but you will be using that image to get to other files you would like to insert. If an image tag is inserted into the post you can delete it if you want. </p> <p> <a href="http://www.tylerhosting.com/b2e/media/blogs/dbell/attachimage.png?mtime=1502468848"><img src="http://www.tylerhosting.com/b2e/media/blogs/dbell/attachimage.png?mtime=1502468848" alt="" width="431" height="56" /></a></p> <p>3. Position your cursor at the point in your post where you want to include one of your uploaded images.</p> <p>4. Go to the attached image in the Images and Attachments section and click on the Locate file icon (bull's eye).</p> <div class="image_block" style="float: right; margin-left: 20px;"><a href="http://www.tylerhosting.com/b2e/media/blogs/dbell/locateimage.png?mtime=1502468848"><img class="loadimg" src="http://www.tylerhosting.com/b2e/media/blogs/dbell/locateimage.png?mtime=1502468848" alt="" width="115" height="121" /></a> </div> <p>5. When the Attach files dialog box is displayed find the file you really want. You may have to change folders to find it. Again, I prefer to use images in the root collection folder.</p> <p>6. Check the box for the file to select it. Don't press Attach. </p> <p>7. Finally, at the bottom, with selected files: change the option to Insert IMG/link into post and press Go.</p> <h3>Formatting Images </h3> <p>The main reason I want the code in the post is so I can customize the image. In order to do that switch to Markup view and find the image's code. It'll begin with something like</p> <blockquote> <pre>&lt;div class="image_block"&gt;&lt;a href=".."&gt;</pre> </blockquote> <p>Two of the modifications that I generally make are to position the image and resize the image to look good in the post. By positioning, I generally float it left or right.</p> <h4>Floating Images</h4> <p>In markup, find the image markup as noted above and change the div to add</p> <blockquote> <pre>style="float:right"</pre> </blockquote> <p>so it looks like this</p> <blockquote> <pre>&lt;div class="image_block" style="float:right"&gt;&lt;a href=".."&gt;</pre> </blockquote> <p>If you are floating, it might also be necessary to adjust the margins by changing it to </p> <blockquote> <pre>style="float:right; margin-left:20px"</pre> </blockquote> <h4>Resizing</h4> <p>The image should show the actual size in the img tag and would look something like this.</p> <blockquote> <pre>width="431" height="56" /&gt;</pre> </blockquote> <p>If the size is not appropriate for the post, I simply change the width to a percentage and drop the height so it would look something like this</p> <blockquote> <pre>width="35" /&gt;</pre> </blockquote> <p>I have used b2evolution for many years, and find it useful for multiple blogs, but I guess these kinds of challenges are one reason it is not so popular as a blogging platform.</p><div class="item_footer"><p><small><a href="https://tylerhosting.com/b2e/dbell.php/images-in-b2evolution">Original post</a> blogged on <a href="http://www.tylerhosting.com/b2e/">Switched Keys</a>.</small></p></div>
Deprecated: Creation of dynamic property autolinks_plugin::$setting_nofollow_auto is deprecated in /home4/tylering/public_html/b2e/plugins/_autolinks.plugin.php on line 439

Deprecated: Creation of dynamic property autolinks_plugin::$setting_autolink_defs_coll_db is deprecated in /home4/tylering/public_html/b2e/plugins/_autolinks.plugin.php on line 442

Deprecated: Creation of dynamic property autolinks_plugin::$setting_autolink_urls is deprecated in /home4/tylering/public_html/b2e/plugins/_autolinks.plugin.php on line 443

Deprecated: Creation of dynamic property autolinks_plugin::$setting_autolink_emails is deprecated in /home4/tylering/public_html/b2e/plugins/_autolinks.plugin.php on line 444

Deprecated: Creation of dynamic property autolinks_plugin::$setting_autolink_username is deprecated in /home4/tylering/public_html/b2e/plugins/_autolinks.plugin.php on line 445

Deprecated: Creation of dynamic property autolinks_plugin::$setting_autolink_tag is deprecated in /home4/tylering/public_html/b2e/plugins/_autolinks.plugin.php on line 446

Deprecated: Creation of dynamic property PluginSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Deprecated: Creation of dynamic property PluginSettings::$plugin_ID is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_pluginsettings.class.php on line 36

Deprecated: Creation of dynamic property PluginSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Deprecated: Creation of dynamic property PluginSettings::$plugin_ID is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_pluginsettings.class.php on line 36

Deprecated: Creation of dynamic property autolinks_plugin::$replacement_link_array is deprecated in /home4/tylering/public_html/b2e/plugins/_autolinks.plugin.php on line 341

Deprecated: Creation of dynamic property videoplug_plugin::$video_width is deprecated in /home4/tylering/public_html/b2e/plugins/videoplug_plugin/_videoplug.plugin.php on line 152

Deprecated: Creation of dynamic property videoplug_plugin::$video_height is deprecated in /home4/tylering/public_html/b2e/plugins/videoplug_plugin/_videoplug.plugin.php on line 153

Deprecated: Creation of dynamic property PluginSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Deprecated: Creation of dynamic property PluginSettings::$plugin_ID is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_pluginsettings.class.php on line 36

Deprecated: Creation of dynamic property PluginSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121

Deprecated: Creation of dynamic property PluginSettings::$plugin_ID is deprecated in /home4/tylering/public_html/b2e/inc/plugins/model/_pluginsettings.class.php on line 36

Deprecated: Creation of dynamic property auto_p_plugin::$use_auto_br is deprecated in /home4/tylering/public_html/b2e/plugins/_auto_p.plugin.php on line 126

Deprecated: Creation of dynamic property auto_p_plugin::$add_p_in_block is deprecated in /home4/tylering/public_html/b2e/plugins/_auto_p.plugin.php on line 127

Deprecated: Creation of dynamic property auto_p_plugin::$skip_tags is deprecated in /home4/tylering/public_html/b2e/plugins/_auto_p.plugin.php on line 128

Deprecated: Creation of dynamic property nofollow_plugin::$setting_rel_options is deprecated in /home4/tylering/public_html/b2e/plugins/_nofollow.plugin.php on line 159

Deprecated: Creation of dynamic property nofollow_plugin::$setting_target_options is deprecated in /home4/tylering/public_html/b2e/plugins/_nofollow.plugin.php on line 172

Many years ago I started using b2evolution for my blog even though it was not the most popular platform. I'm still using it. Although it is complex, it gives me options that don't exist in other platforms. Now that it has expanded to include other types of collections (photo blogs, manuals, etc), it is even more complex. Unfortunately, the image insertion routines in b2evolution are quite inflexible, and I suspect that is one reason it will never be very popular.

The guide says you should attach the image where you want it, but it doesn't include the file in the page markup and instead includes a tag that identifies the image. The logic presented in the on-line forums is that you can adjust the stylesheet and php to apply uniformly to all images. You can put the image in different sections (teaser, cover, in-line) of the post and it supposedly is more efficient that way.

The Issue

Although you have multiple options for placement (vertically) in a post, if it's an in-line image you can't see it in the editor. Instead you see . Additionally you can't modify the formatting of the image. That's where the problems resides. If b2evolution included the code in-line (like it used to) I could modify the HTML/CSS to format the image. 

Emulating a print publication, I like to wrap text around some images, and like adjusting the size to make it look more balanced. Well, there is a way to include the markup, but it's not intuitive.

The Work Around

I've discovered after inserting all my images that there is a viable workaround to get the code into the post, something that used to be an option in the editor in past versions.

1. Go to the b2e Back-office and select Files > Browse and upload the images for the post. I prefer to put them in the root collection folder, not the quick-uploads.

2. From the post, attach any image to the post (ideally an inline). The easiest way is to select Attach existing files and select one. You won't be including that in the post, but you will be using that image to get to other files you would like to insert. If an image tag is inserted into the post you can delete it if you want. 

 

3. Position your cursor at the point in your post where you want to include one of your uploaded images.

4. Go to the attached image in the Images and Attachments section and click on the Locate file icon (bull's eye).

 

5. When the Attach files dialog box is displayed find the file you really want. You may have to change folders to find it. Again, I prefer to use images in the root collection folder.

6. Check the box for the file to select it. Don't press Attach. 

7. Finally, at the bottom, with selected files: change the option to Insert IMG/link into post and press Go.

Formatting Images 

The main reason I want the code in the post is so I can customize the image. In order to do that switch to Markup view and find the image's code. It'll begin with something like

<div class="image_block"><a href="..">

Two of the modifications that I generally make are to position the image and resize the image to look good in the post. By positioning, I generally float it left or right.

Floating Images

In markup, find the image markup as noted above and change the div to add

style="float:right"

so it looks like this

<div class="image_block" style="float:right"><a href="..">

If you are floating, it might also be necessary to adjust the margins by changing it to 

style="float:right; margin-left:20px"

Resizing

The image should show the actual size in the img tag and would look something like this.

width="431" height="56" />

If the size is not appropriate for the post, I simply change the width to a percentage and drop the height so it would look something like this

width="35" />

I have used b2evolution for many years, and find it useful for multiple blogs, but I guess these kinds of challenges are one reason it is not so popular as a blogging platform.

]]>
https://tylerhosting.com/b2e/dbell.php/images-in-b2evolution#comments https://tylerhosting.com/b2e/dbell.php?tempskin=_rss2&disp=comments&p=394
Hoot With a Ribbon, MDI, and Inheritance https://tylerhosting.com/b2e/dbell.php/hoot-with-a-ribbon Sun, 05 Mar 2017 04:55:00 +0000 Dana Bell Information Technology Computing 382@https://tylerhosting.com/b2e/
Deprecated: Creation of dynamic property Item::$cache_has_content_parts is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 4911

Deprecated: Creation of dynamic property Item::$renderers_validated is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 11107

Deprecated: Creation of dynamic property Item::$pages is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 2412

Deprecated: Creation of dynamic property ItemSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121
<p>I just released a new beta version of <a title="Hoot Scrabble study tools" href="http://www.tylerhosting.com/hoot/" target="_blank">Hoot</a>. While it is fully functioning, it does involve significant changes in the way Hoot works. With version 1.9.0, Hoot employs an MDI (Multiple document interface). Previously, Hoot opened new windows for different types of searches. These windows filled the taskbar and were scattered across the desktop. With MDI all windows are contained in the program's main menu.</p> <p>Another significant difference is the use of inherited forms. While users should not care, it does mean the code is smaller and (theoretically) faster. For me, it means changes can be made to the interface easier.</p> <p>Finally, the new Hoot includes a ribbon, like you might have seen in Microsoft Office applications beginning in 2007. While this ribbon is not from Microsoft, it is a very good look-alike. All of this may sound boring, but for a developer it is a little fascinating, figuring out how things work, as well as how to work around limitations.</p> <h2>Multiple Document Interface</h2> <p>With the MDI I could avoid creating new form for each call and instead open them as child windows. Other than setting the appropriate flags on the parent form, the only thing I had to do different is open the forms appropriately for the MDI. One standard way to open such forms is with code like what I've used. This also cascades the new form over the last active child.</p> <blockquote> <pre>private void OpenChild(Form child)<br /> {<br /> child.MdiParent = this;<br /> Form last = new Form();<br /> if (this.MdiChildren.Count() &gt; 0)<br /> foreach (Form f in this.MdiChildren)<br /> if (f == this.ActiveMdiChild)<br /> {<br /> last = f;<br /> child.Location = new Point(last.Location.X + 25, last.Location.Y + 25);<br /> break;<br /> }<br /> child.Show();<br /> }</pre> </blockquote> <p>If I want to insure only one copy of that form is used I simply check for the form name among the children.</p> <blockquote> <pre>private void OpenOneChild(Form child)<br /> {<br /> if (!(FindChild(child.Name) == null))<br /> {<br /> child.Activate();<br /> return;<br /> }<br /> OpenChild(child);<br /> }</pre> <pre>private Form FindChild(string name)<br /> {<br /> foreach (Form f in this.MdiChildren)<br /> {<br /> if ((string)f.Text == name)<br /> return (f);<br /> }<br /> return null;<br /> }</pre> </blockquote> <p>Of course, if I wanted to open a form from a child window, I would use a different method.</p> <blockquote> <pre>private void OpenSibling(Form child)<br /> {<br /> child.MdiParent = this.ParentForm;<br /> Form last = new Form();<br /> if (this.ParentForm.MdiChildren.Count() &gt; 0)<br /> foreach (Form f in this.ParentForm.MdiChildren)<br /> if (f == this.ParentForm.ActiveMdiChild)<br /> {<br /> last = f;<br /> child.Location = new Point(last.Location.X + 25, last.Location.Y + 25);<br /> break;<br /> }<br /> child.Show();<br /> }</pre> </blockquote> <p> </p> <h2>Inheritance</h2> <p>When I mentioned Inherited forms on one discussion board one of the responses started with "ouch, ouch, ouch". Well, it's not so bad. With inheritance in C# you can't normally pass parameters to an inherited form, so I found a workaround. While inherited forms apparently can't take parameters in their constructors, at least not directly, you can access the controls of the inherited form and force a parameter.</p> <p>1. Add a label named lblTrigger (public or protected)<br />2. Add an event to the label for the TextChanged event</p> <blockquote> <pre>private void lblTrigger_TextChanged(object sender, EventArgs e)<br /> {<br /> switch (lblTrigger.Text)<br /> {<br /> case "Hooks": ShowHooks(); break;<br /> case "Words": HideHooks(); break;<br /> case "Slides": btnSlideShow_Click(sender, e); break;<br /> case "ChangeLanguage": PopulateResources(); break;<br /> }<br /> lblTrigger.Text = "Trigger";<br /> }</pre> </blockquote> <p>3. Change that label from the ribbon or another form</p> <blockquote> <pre>public static void SetTrigger(string text, System.Windows.Forms.Form frm) {<br /> if (frm == null)<br /> return;<br /> foreach (System.Windows.Forms.Control ctl in frm.Controls)<br /> {<br /> if (ctl.Name.Equals("lblTrigger"))<br /> ctl.Text = text;<br /> }<br /> }</pre> </blockquote> <p>You're not limited to one label, either. You can add parameters to use with a different label. That's what I've done using lblParameters included in one of the code segments below. Set the parameters, then "pull" the trigger.</p> <p>In one case "SavedSearch" is the text I set for the trigger.</p> <blockquote> <pre>case "SavedSearch": OpenFromRecent(); break;</pre> </blockquote> <p>That then calls this method which simulates a button click on the form.</p> <blockquote> <pre>private void OpenFromRecent()<br /> {<br /> specs = Utilities.LoadSearch(lblParameters.Text);<br /> if (specs == null)<br /> return;<br /> cboSearchType.SelectedIndex = Array.IndexOf(english, specs.searchtype);<br /> if (!(cboSearchType.SelectedIndex == -1))<br /> {<br /> txtSearch.Text = specs.letters;<br /> cboMin.SelectedIndex = specs.minLen - 1;<br /> cboMax.SelectedIndex = specs.maxLen - 1;<br /> cboBegin.Text = specs.prefix;<br /> cboEnd.Text = specs.suffix;<br /> txtFilter.Text = specs.filter;<br /> }<br /> btnSearch_Click(this, EventArgs.Empty);<br /> }</pre> </blockquote> <h2>Ribbon</h2> <p>The ribbon I am using in this project is the one mentioned in the Code Project article at <a title="C# Ribbon" href="https://www.codeproject.com/articles/364272/easily-add-a-ribbon-into-a-winforms-application-cs" target="_blank">https://www.codeproject.com/articles/364272/easily-add-a-ribbon-into-a-winforms-application-cs</a>. It's a third-party ribbon for C#, not WPF or other Microsoft. While it looks and performs well, there is a limited documentation for it. The intellisense and integration with Windows is good, and many items are similar. One of my biggest challenges was determining how to use the Recent Items list.</p> <h3>Recent items</h3> <p>One thing that was not so easy to understand was the use of the Recent Items list in the Orb menu. Determining how to create recent items dynamically, however, was one of the biggest accomplishments recently. My last blog entry touched on recent items and using the C# .Designer file to figure out how to create them. Actual implementation was a little more difficult. With my implementation I created a new class with properties of the recent item that I would use.</p> <h4>The Recent Item</h4> <blockquote> <pre>public RecentItem(string tag, string text)<br /> {<br /> ItemID = 0;<br /> ItemTag = tag;<br /> ItemText = text;<br /> UserID = Properties.Settings.Default.User;<br /> }</pre> </blockquote> <p>The text is the filename. The tag indicates the type of item since the items are not identified by file extension. ItemID will be updated when saved to the database. The database fields are similar to the class fields.</p> <h4>Loading Items on form load:</h4> <blockquote> <pre>.. <br />List&lt;RecentItem&gt; load = new List&lt;RecentItem&gt;(); <br />load = DBManager.LoadRecentItems(); <br />AddRecentItems(load); // see below <br />ribbonMain.OrbDropDown.RecentItems.Reverse(); <br />..</pre> </blockquote> <p>Reverse is used to put latest items at the top. The ID is set by the database using autonumber so the oldest items have the lowest ID and are loaded first.</p> <blockquote> <pre> private void AddRecentItems(List&lt;RecentItem&gt; recentItems) {<br /> foreach (RecentItem item in recentItems)<br /> DBManager.OrbAddRecentItem(item); // see below<br /> }</pre> </blockquote> <h4>Adds items to Recent Items from database</h4> <blockquote> <pre>public static void OrbAddRecentItem(RecentItem recent)<br /> {<br /> frmHootGold top = (frmHootGold)System.Windows.Forms.Application.OpenForms["frmHootGold"];<br /> RibbonOrbRecentItem adder = new RibbonOrbRecentItem();<br /> adder.Tag = recent.ItemTag;<br /> adder.Text = recent.ItemText;<br /> adder.Value = recent.ItemID.ToString();<br /> top.ribbonMain.OrbDropDown.RecentItems.Add(adder);<br /> adder.Click += new System.EventHandler(top.OrbRecent_Click); // see below<br /> }</pre> </blockquote> <p>When the items are added to the list, either as new items or when loaded from the database, the click event is set.</p> <h4>Calling Form</h4> <p>A separate method is used when actually adding a new item that has one difference to add the new item to the list that has already been sorted in descending order.</p> <blockquote> <pre> public static void OrbInsertRecentItem(RecentItem recent)<br /> ..<br /> top.ribbonMain.OrbDropDown.RecentItems.Insert(0, adder);</pre> </blockquote> <p>That's done from one of the child windows with code segment something like this</p> <blockquote> <pre>RecentItem adder = new RecentItem("SavedSearch", searchFile);<br />DBManager.AddRecentItem(adder);<br />DBManager.OrbInsertRecentItem(adder);</pre> </blockquote> <h4>The Recent Item List</h4> <p>When a user clicks an item on the Recent list, the following method uses the trigger and parameters mentioned earlier to pass that information to a new child form.</p> <blockquote> <pre>public void OrbRecent_Click(object sender, EventArgs e)<br /> {<br /> RibbonOrbRecentItem item = (RibbonOrbRecentItem)sender;<br /> Form form = new Form();<br /> switch (item.Tag.ToString())<br /> {<br /> case "SavedSearch": form = new frmCombo(); break;<br /> case "Textfile": form = new frmTextfiles(); break;<br /> }<br /> OpenChild(form);<br /> MDIUtils.SetParms(item.Text, form);<br /> MDIUtils.SetTrigger((string)item.Tag, form);<br /> }</pre> </blockquote> <p>One of the things I learned about Recent Items is that there is no obvious way to enable user-deletion of items. I notice Word doesn't have that either, nor does Windows, so I decided not to worry about it.</p> <p>If you use this in a program you may notice that the items are added to Windows list of Recent Items, but it's not because of this method. It's simply because they were files that "you" opened. Anyway, this is my contribution to the C# Ribbon knowledge base.</p><div class="item_footer"><p><small><a href="https://tylerhosting.com/b2e/dbell.php/hoot-with-a-ribbon">Original post</a> blogged on <a href="http://www.tylerhosting.com/b2e/">Switched Keys</a>.</small></p></div>
I just released a new beta version of Hoot. While it is fully functioning, it does involve significant changes in the way Hoot works. With version 1.9.0, Hoot employs an MDI (Multiple document interface). Previously, Hoot opened new windows for different types of searches. These windows filled the taskbar and were scattered across the desktop. With MDI all windows are contained in the program's main menu.

Another significant difference is the use of inherited forms. While users should not care, it does mean the code is smaller and (theoretically) faster. For me, it means changes can be made to the interface easier.

Finally, the new Hoot includes a ribbon, like you might have seen in Microsoft Office applications beginning in 2007. While this ribbon is not from Microsoft, it is a very good look-alike. All of this may sound boring, but for a developer it is a little fascinating, figuring out how things work, as well as how to work around limitations.

Multiple Document Interface

With the MDI I could avoid creating new form for each call and instead open them as child windows. Other than setting the appropriate flags on the parent form, the only thing I had to do different is open the forms appropriately for the MDI. One standard way to open such forms is with code like what I've used. This also cascades the new form over the last active child.

private void OpenChild(Form child)
{
child.MdiParent = this;
Form last = new Form();
if (this.MdiChildren.Count() > 0)
foreach (Form f in this.MdiChildren)
if (f == this.ActiveMdiChild)
{
last = f;
child.Location = new Point(last.Location.X + 25, last.Location.Y + 25);
break;
}
child.Show();
}

If I want to insure only one copy of that form is used I simply check for the form name among the children.

private void OpenOneChild(Form child)
{
if (!(FindChild(child.Name) == null))
{
child.Activate();
return;
}
OpenChild(child);
}
private Form FindChild(string name)
{
foreach (Form f in this.MdiChildren)
{
if ((string)f.Text == name)
return (f);
}
return null;
}

Of course, if I wanted to open a form from a child window, I would use a different method.

private void OpenSibling(Form child)
{
child.MdiParent = this.ParentForm;
Form last = new Form();
if (this.ParentForm.MdiChildren.Count() > 0)
foreach (Form f in this.ParentForm.MdiChildren)
if (f == this.ParentForm.ActiveMdiChild)
{
last = f;
child.Location = new Point(last.Location.X + 25, last.Location.Y + 25);
break;
}
child.Show();
}

 

Inheritance

When I mentioned Inherited forms on one discussion board one of the responses started with "ouch, ouch, ouch". Well, it's not so bad. With inheritance in C# you can't normally pass parameters to an inherited form, so I found a workaround. While inherited forms apparently can't take parameters in their constructors, at least not directly, you can access the controls of the inherited form and force a parameter.

1. Add a label named lblTrigger (public or protected)
2. Add an event to the label for the TextChanged event

private void lblTrigger_TextChanged(object sender, EventArgs e)
{
switch (lblTrigger.Text)
{
case "Hooks": ShowHooks(); break;
case "Words": HideHooks(); break;
case "Slides": btnSlideShow_Click(sender, e); break;
case "ChangeLanguage": PopulateResources(); break;
}
lblTrigger.Text = "Trigger";
}

3. Change that label from the ribbon or another form

public static void SetTrigger(string text, System.Windows.Forms.Form frm) {
if (frm == null)
return;
foreach (System.Windows.Forms.Control ctl in frm.Controls)
{
if (ctl.Name.Equals("lblTrigger"))
ctl.Text = text;
}
}

You're not limited to one label, either. You can add parameters to use with a different label. That's what I've done using lblParameters included in one of the code segments below. Set the parameters, then "pull" the trigger.

In one case "SavedSearch" is the text I set for the trigger.

case "SavedSearch": OpenFromRecent(); break;

That then calls this method which simulates a button click on the form.

private void OpenFromRecent()
{
specs = Utilities.LoadSearch(lblParameters.Text);
if (specs == null)
return;
cboSearchType.SelectedIndex = Array.IndexOf(english, specs.searchtype);
if (!(cboSearchType.SelectedIndex == -1))
{
txtSearch.Text = specs.letters;
cboMin.SelectedIndex = specs.minLen - 1;
cboMax.SelectedIndex = specs.maxLen - 1;
cboBegin.Text = specs.prefix;
cboEnd.Text = specs.suffix;
txtFilter.Text = specs.filter;
}
btnSearch_Click(this, EventArgs.Empty);
}

Ribbon

The ribbon I am using in this project is the one mentioned in the Code Project article at https://www.codeproject.com/articles/364272/easily-add-a-ribbon-into-a-winforms-application-cs. It's a third-party ribbon for C#, not WPF or other Microsoft. While it looks and performs well, there is a limited documentation for it. The intellisense and integration with Windows is good, and many items are similar. One of my biggest challenges was determining how to use the Recent Items list.

Recent items

One thing that was not so easy to understand was the use of the Recent Items list in the Orb menu. Determining how to create recent items dynamically, however, was one of the biggest accomplishments recently. My last blog entry touched on recent items and using the C# .Designer file to figure out how to create them. Actual implementation was a little more difficult. With my implementation I created a new class with properties of the recent item that I would use.

The Recent Item

public RecentItem(string tag, string text)
{
ItemID = 0;
ItemTag = tag;
ItemText = text;
UserID = Properties.Settings.Default.User;
}

The text is the filename. The tag indicates the type of item since the items are not identified by file extension. ItemID will be updated when saved to the database. The database fields are similar to the class fields.

Loading Items on form load:

.. 
List<RecentItem> load = new List<RecentItem>();
load = DBManager.LoadRecentItems();
AddRecentItems(load); // see below
ribbonMain.OrbDropDown.RecentItems.Reverse();
..

Reverse is used to put latest items at the top. The ID is set by the database using autonumber so the oldest items have the lowest ID and are loaded first.

 private void AddRecentItems(List<RecentItem> recentItems) {
foreach (RecentItem item in recentItems)
DBManager.OrbAddRecentItem(item); // see below
}

Adds items to Recent Items from database

public static void OrbAddRecentItem(RecentItem recent)
{
frmHootGold top = (frmHootGold)System.Windows.Forms.Application.OpenForms["frmHootGold"];
RibbonOrbRecentItem adder = new RibbonOrbRecentItem();
adder.Tag = recent.ItemTag;
adder.Text = recent.ItemText;
adder.Value = recent.ItemID.ToString();
top.ribbonMain.OrbDropDown.RecentItems.Add(adder);
adder.Click += new System.EventHandler(top.OrbRecent_Click); // see below
}

When the items are added to the list, either as new items or when loaded from the database, the click event is set.

Calling Form

A separate method is used when actually adding a new item that has one difference to add the new item to the list that has already been sorted in descending order.

 public static void OrbInsertRecentItem(RecentItem recent)
..
top.ribbonMain.OrbDropDown.RecentItems.Insert(0, adder);

That's done from one of the child windows with code segment something like this

RecentItem adder = new RecentItem("SavedSearch", searchFile);
DBManager.AddRecentItem(adder);
DBManager.OrbInsertRecentItem(adder);

The Recent Item List

When a user clicks an item on the Recent list, the following method uses the trigger and parameters mentioned earlier to pass that information to a new child form.

public void OrbRecent_Click(object sender, EventArgs e)
{
RibbonOrbRecentItem item = (RibbonOrbRecentItem)sender;
Form form = new Form();
switch (item.Tag.ToString())
{
case "SavedSearch": form = new frmCombo(); break;
case "Textfile": form = new frmTextfiles(); break;
}
OpenChild(form);
MDIUtils.SetParms(item.Text, form);
MDIUtils.SetTrigger((string)item.Tag, form);
}

One of the things I learned about Recent Items is that there is no obvious way to enable user-deletion of items. I notice Word doesn't have that either, nor does Windows, so I decided not to worry about it.

If you use this in a program you may notice that the items are added to Windows list of Recent Items, but it's not because of this method. It's simply because they were files that "you" opened. Anyway, this is my contribution to the C# Ribbon knowledge base.

]]>
https://tylerhosting.com/b2e/dbell.php/hoot-with-a-ribbon#comments https://tylerhosting.com/b2e/dbell.php?tempskin=_rss2&disp=comments&p=382
Programmatically - Let Designer show you https://tylerhosting.com/b2e/dbell.php/programmatically-let-designer-show-you Mon, 27 Feb 2017 23:48:00 +0000 Dana Bell Information Technology Computing 381@https://tylerhosting.com/b2e/
Deprecated: Creation of dynamic property Item::$cache_has_content_parts is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 4911

Deprecated: Creation of dynamic property Item::$renderers_validated is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 11107

Deprecated: Creation of dynamic property Item::$pages is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 2412

Deprecated: Creation of dynamic property ItemSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121
<p>The web is full of queries about how to accomplish something programmatically. This can't help with all of them, but if it has to do with C# in Visual Studio, this might guide you in the right direction. Visual Studio is robust enough to do a lot of things for you, but sometimes you need a variation of one of those automatic features. Well, it's easy to determine that than it might appear.</p> <p>When VS creates an item, it does it with code. Finding how it's done may be as simple as looking at the code behind, i.e. in the form's .Designer file. Specifically, it answers the common questions:<br />What's the name of the class you use to create the item?<br />What's the name of the parent class, and how do you add an item to it?</p> <p>Here's a couple of examples:</p> <p>Example 1: I have a form that inherits from another form. The base form includes a complex context menu so derived forms do not have to duplicate that work repeatedly. But there are a couple of forms that need some additional items added to the list. How can I dynamically add items to that context menu for some forms?</p> <p>In order to see what Designer does, add the items to a copy of the base form in design mode (or look at a previously added item). In my case, there were items name popLoadSearch, popSaveSearch, and a separator.</p> <p>Then, open the .Designer file and search for the names. Each was found four times. You can verify some of the statements by looking at the properties of the previously added items. The first set were statements that create the objects and the rest configured the objects and added them to the context menu collection. This is what I found. </p> <h4>Create objects</h4> <blockquote> <pre>this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();<br />this.popLoadSearch = new System.Windows.Forms.ToolStripMenuItem();<br />this.popSaveSearch = new System.Windows.Forms.ToolStripMenuItem();</pre> </blockquote> <h4>Configure objects</h4> <blockquote> <pre>// <br />// toolStripSeparator1<br />// <br />this.toolStripSeparator1.Name = "toolStripSeparator1";<br />this.toolStripSeparator1.Size = new System.Drawing.Size(162, 6);<br />// <br />// popLoadSearch<br />// <br />this.popLoadSearch.Name = "popLoadSearch";<br />this.popLoadSearch.Size = new System.Drawing.Size(165, 22);<br />this.popLoadSearch.Text = "Load Search";<br />this.popLoadSearch.Click += new System.EventHandler(this.popLoadSearch_Click);<br />// <br />// popSaveSearch<br />// <br />this.popSaveSearch.Name = "popSaveSearch";<br />this.popSaveSearch.Size = new System.Drawing.Size(165, 22);<br />this.popSaveSearch.Text = "Save Search";<br />this.popSaveSearch.Click += new System.EventHandler(this.popSaveSearch_Click);</pre> </blockquote> <h4>Add objects to collection</h4> <blockquote> <pre>this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {<br />this.popLoadSearch,<br />this.popSaveSearch});</pre> </blockquote> <h4>Declare variables</h4> <blockquote> <pre>private System.Windows.Forms.ToolStripMenuItem popLoadSearch;<br />private System.Windows.Forms.ToolStripMenuItem popSaveSearch;<br />private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;</pre> </blockquote> <p>Yes, this looks backward since variables have to be declared before they are used but in Designer the commands are contained in the InitializeComponent method, while the declarations are in the class.  Just remember to move the declarations to the top, and preferably instantiate them at the same time. I also noticed the command to size the menustrip, so I figure I needed to change that too.</p> <blockquote> <pre>this.contextMenuStrip1.Size = new System.Drawing.Size(166, 484);</pre> </blockquote> <p>After removing some reference terms (this., private, Systems.Windows.Forms.), renaming the separator, and compressing some of the commands, this is what my addition looks like. I include a command in the form load method to execute this.</p> <blockquote> <pre>private void AddContextItems()<br />{<br /> // Declare Variables<br /> ToolStripSeparator topSeparator = new ToolStripSeparator();<br /> ToolStripMenuItem popLoadSearch = new ToolStripMenuItem();<br /> ToolStripMenuItem popSaveSearch = new ToolStripMenuItem();<br /> // Configure objects<br /> topSeparator.Name = "Separator";<br /> topSeparator.Size = new System.Drawing.Size(162, 6);<br /> // popLoadSearch<br /> popLoadSearch.Name = "popLoadSearch";<br /> popLoadSearch.Size = new System.Drawing.Size(165, 22);<br /> popLoadSearch.Text = "Load Search";<br /> popLoadSearch.Click += new System.EventHandler(popLoadSearch_Click);<br /> // popSaveSearch<br /> popSaveSearch.Name = "popSaveSearch";<br /> popSaveSearch.Size = new System.Drawing.Size(165, 22);<br /> popSaveSearch.Text = "Save Search";<br /> popSaveSearch.Click += new System.EventHandler(popSaveSearch_Click);<br /> //add objects to collection<br /> this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {<br /> topSeparator,<br /> popLoadSearch,<br /> popSaveSearch});<br /> // resize the menu<br /> this.contextMenuStrip1.Size = new System.Drawing.Size(166, 534); // 484 + 22 + 22 + 6<br /> }</pre> </blockquote> <p>Of course, I also had to create the methods assigned to the Click method of each.</p> <p>Example 2: For my program <a title="Hoot Word Game Study Tool" href="http://www.tylerhosting.com/hoot/" target="_blank">Hoot</a> I'm adding a Ribbon wrapper for C# WinForms and I need to dynamically add new recent items to the Orb menu. You can read about this Ribbon at <a title="Easily Add a Ribbon into a WinForms Application (C#)" href="https://www.codeproject.com/articles/364272/easily-add-a-ribbon-into-a-winforms-application-cs" target="_blank">https://www.codeproject.com/articles/364272/easily-add-a-ribbon-into-a-winforms-application-cs</a>. Other than the basic introduction for getting started there's not much documentation since it's not officially Microsoft (like WPF), so I have to figure things out. The Orb menu includes a list of items that are commonly used in other programs to list recent items opened. I want to do that but don't know the classes or methods to use. Intellisense is not always the easiest way to figure that out, so I create an item in design mode called OrbRecent and look for it in the Designer code.</p> <h4>Instantiation</h4> <blockquote> <pre>this.OrbRecent = new System.Windows.Forms.RibbonOrbRecentItem();</pre> </blockquote> <h4>Add to collection</h4> <blockquote> <pre>this.ribbonMain.OrbDropDown.RecentItems.Add(this.OrbRecent);</pre> </blockquote> <h4>Configuration</h4> <blockquote> <pre>// <br />// OrbRecent<br />// <br />this.OrbRecent.Image = ((System.Drawing.Image)(resources.GetObject <br /> ("OrbRecent.Image")));<br />this.OrbRecent.SmallImage = ((System.Drawing.Image)(resources.GetObject <br /> ("OrbRecent.SmallImage")));<br />this.OrbRecent.Text = "Recent";</pre> </blockquote> <h4>Declaration</h4> <blockquote> <pre>private System.Windows.Forms.RibbonOrbRecentItem OrbRecent;</pre> </blockquote> <p>Now that I know how VS created and added the item to the collection, I can create a method to do that dynamically, and adjust it to my future needs. I will add it to my Utilities class and use a database table to store the entries. Of course, I'll have to reverse sort the entries so the most recent are on top, and to keep the list at a reasonable size I will need to monitor the size and remove old items. </p> <blockquote> <pre>AddRecent(string spec) {<br /> RibbonOrbRecentItem adder = new RibbonOrbRecentItem();<br /> adder.Text = spec;<br /> this.OrbRecent.Image = ((System.Drawing.Image)(resources.GetObject <br /> ("OrbRecent.Image")));<br /> this.OrbRecent.SmallImage = ((System.Drawing.Image)(resources.GetObject <br /> ("OrbRecent.SmallImage")));<br /> ribbonMain.OrbDropDown.RecentItems.Add(spec);<br />}</pre> </blockquote> <p>Visual Studio's Designer code taught me that.</p><div class="item_footer"><p><small><a href="https://tylerhosting.com/b2e/dbell.php/programmatically-let-designer-show-you">Original post</a> blogged on <a href="http://www.tylerhosting.com/b2e/">Switched Keys</a>.</small></p></div>
The web is full of queries about how to accomplish something programmatically. This can't help with all of them, but if it has to do with C# in Visual Studio, this might guide you in the right direction. Visual Studio is robust enough to do a lot of things for you, but sometimes you need a variation of one of those automatic features. Well, it's easy to determine that than it might appear.

When VS creates an item, it does it with code. Finding how it's done may be as simple as looking at the code behind, i.e. in the form's .Designer file. Specifically, it answers the common questions:
What's the name of the class you use to create the item?
What's the name of the parent class, and how do you add an item to it?

Here's a couple of examples:

Example 1: I have a form that inherits from another form. The base form includes a complex context menu so derived forms do not have to duplicate that work repeatedly. But there are a couple of forms that need some additional items added to the list. How can I dynamically add items to that context menu for some forms?

In order to see what Designer does, add the items to a copy of the base form in design mode (or look at a previously added item). In my case, there were items name popLoadSearch, popSaveSearch, and a separator.

Then, open the .Designer file and search for the names. Each was found four times. You can verify some of the statements by looking at the properties of the previously added items. The first set were statements that create the objects and the rest configured the objects and added them to the context menu collection. This is what I found. 

Create objects

this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.popLoadSearch = new System.Windows.Forms.ToolStripMenuItem();
this.popSaveSearch = new System.Windows.Forms.ToolStripMenuItem();

Configure objects

// 
// toolStripSeparator1
//
this.toolStripSeparator1.Name = "toolStripSeparator1";
this.toolStripSeparator1.Size = new System.Drawing.Size(162, 6);
//
// popLoadSearch
//
this.popLoadSearch.Name = "popLoadSearch";
this.popLoadSearch.Size = new System.Drawing.Size(165, 22);
this.popLoadSearch.Text = "Load Search";
this.popLoadSearch.Click += new System.EventHandler(this.popLoadSearch_Click);
//
// popSaveSearch
//
this.popSaveSearch.Name = "popSaveSearch";
this.popSaveSearch.Size = new System.Drawing.Size(165, 22);
this.popSaveSearch.Text = "Save Search";
this.popSaveSearch.Click += new System.EventHandler(this.popSaveSearch_Click);

Add objects to collection

this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.popLoadSearch,
this.popSaveSearch});

Declare variables

private System.Windows.Forms.ToolStripMenuItem popLoadSearch;
private System.Windows.Forms.ToolStripMenuItem popSaveSearch;
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;

Yes, this looks backward since variables have to be declared before they are used but in Designer the commands are contained in the InitializeComponent method, while the declarations are in the class.  Just remember to move the declarations to the top, and preferably instantiate them at the same time. I also noticed the command to size the menustrip, so I figure I needed to change that too.

this.contextMenuStrip1.Size = new System.Drawing.Size(166, 484);

After removing some reference terms (this., private, Systems.Windows.Forms.), renaming the separator, and compressing some of the commands, this is what my addition looks like. I include a command in the form load method to execute this.

private void AddContextItems()
{
// Declare Variables
ToolStripSeparator topSeparator = new ToolStripSeparator();
ToolStripMenuItem popLoadSearch = new ToolStripMenuItem();
ToolStripMenuItem popSaveSearch = new ToolStripMenuItem();
// Configure objects
topSeparator.Name = "Separator";
topSeparator.Size = new System.Drawing.Size(162, 6);
// popLoadSearch
popLoadSearch.Name = "popLoadSearch";
popLoadSearch.Size = new System.Drawing.Size(165, 22);
popLoadSearch.Text = "Load Search";
popLoadSearch.Click += new System.EventHandler(popLoadSearch_Click);
// popSaveSearch
popSaveSearch.Name = "popSaveSearch";
popSaveSearch.Size = new System.Drawing.Size(165, 22);
popSaveSearch.Text = "Save Search";
popSaveSearch.Click += new System.EventHandler(popSaveSearch_Click);
//add objects to collection
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
topSeparator,
popLoadSearch,
popSaveSearch});
// resize the menu
this.contextMenuStrip1.Size = new System.Drawing.Size(166, 534); // 484 + 22 + 22 + 6
}

Of course, I also had to create the methods assigned to the Click method of each.

Example 2: For my program Hoot I'm adding a Ribbon wrapper for C# WinForms and I need to dynamically add new recent items to the Orb menu. You can read about this Ribbon at https://www.codeproject.com/articles/364272/easily-add-a-ribbon-into-a-winforms-application-cs. Other than the basic introduction for getting started there's not much documentation since it's not officially Microsoft (like WPF), so I have to figure things out. The Orb menu includes a list of items that are commonly used in other programs to list recent items opened. I want to do that but don't know the classes or methods to use. Intellisense is not always the easiest way to figure that out, so I create an item in design mode called OrbRecent and look for it in the Designer code.

Instantiation

this.OrbRecent = new System.Windows.Forms.RibbonOrbRecentItem();

Add to collection

this.ribbonMain.OrbDropDown.RecentItems.Add(this.OrbRecent);

Configuration

// 
// OrbRecent
//
this.OrbRecent.Image = ((System.Drawing.Image)(resources.GetObject
("OrbRecent.Image")));
this.OrbRecent.SmallImage = ((System.Drawing.Image)(resources.GetObject
("OrbRecent.SmallImage")));
this.OrbRecent.Text = "Recent";

Declaration

private System.Windows.Forms.RibbonOrbRecentItem OrbRecent;

Now that I know how VS created and added the item to the collection, I can create a method to do that dynamically, and adjust it to my future needs. I will add it to my Utilities class and use a database table to store the entries. Of course, I'll have to reverse sort the entries so the most recent are on top, and to keep the list at a reasonable size I will need to monitor the size and remove old items. 

AddRecent(string spec) {
RibbonOrbRecentItem adder = new RibbonOrbRecentItem();
adder.Text = spec;
this.OrbRecent.Image = ((System.Drawing.Image)(resources.GetObject
("OrbRecent.Image")));
this.OrbRecent.SmallImage = ((System.Drawing.Image)(resources.GetObject
("OrbRecent.SmallImage")));
ribbonMain.OrbDropDown.RecentItems.Add(spec);
}

Visual Studio's Designer code taught me that.

]]>
https://tylerhosting.com/b2e/dbell.php/programmatically-let-designer-show-you#comments https://tylerhosting.com/b2e/dbell.php?tempskin=_rss2&disp=comments&p=381
Managing Localization in Combo Boxes https://tylerhosting.com/b2e/dbell.php/managing-localization-in-combo-boxes Wed, 18 Jan 2017 19:41:00 +0000 Dana Bell Information Technology Computing Code Project 377@https://tylerhosting.com/b2e/
Deprecated: Creation of dynamic property Item::$cache_has_content_parts is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 4911

Deprecated: Creation of dynamic property Item::$renderers_validated is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 11107

Deprecated: Creation of dynamic property Item::$pages is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 2412

Deprecated: Creation of dynamic property ItemSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121
<h2>Introduction</h2> <p>This example combines the use of combo boxes, a separate DataSource, and localized <code>string</code>s for alternate cultures.</p> <h2>Background</h2> <p>Using a combo box, programmers can use a selected item as a variable or parameter within a single method. In other cases, the combo box is a collection of options, each of which executes a different method. The combo box can be populated within the design, or assigned using a <code>DataSource</code>. Even a simple <code>string</code> array can be used for that. Processing the selection from the combo box when executing a different method for each combo box entry can be done using the index of the selected item.</p> <pre lang="cs">string[] special = { "Select", "Vowels", "DoubleI", "DoubleU", "NoVowels", "Consonants", "QNotU", "Palins", "HighFives", "HighFours", "NoHooks"}; cboSearch.DataSource = special; switch (cboSearch.SelectedIndex) { case 1: btnVowelHeavy_Click(sender, e); break; ... case 5: btnConsonantDumps_Click(sender, e); break; ... }</pre> <h2>An Alternate</h2> <p>When using the combo box selected index the routine may have to be modified each time a new item is added or items are moved around. If we add an item to the middle of the list, we have to figure out what the item number will be and then change the <code>select</code> statement. Case 2 may be the new one, so the original case 2 has to be changed to case 3, case 3 to case 4, etc.</p> <p>To avoid that, it is possible to use the selected item's content. Using the actual <code>string</code> in the collection is often a clearer way to code.</p> <pre lang="cs">switch(cboSearch.SelectedText) { case "Vowels": ...</pre> <p>Thus, case 1 would be replaced with case "<code>Vowels</code>". Additions to the collection will not require any reordering.</p> <h2>The Challenge</h2> <p>This works well until you have to support localization, that is, present different collections of <code>string</code>s based on the language selected. The <code>string</code> used in a <code>switch</code> statement must be a constant, so you can't use:</p> <pre lang="cs">switch (cboSearch.SelectedText) { case rm.GetString("Vowels"): ...</pre> <p>We could go back to using indexes, but we want to avoid going back to that. This is where the <code>CultureCombo</code> comes in handy. This simple class and the supporting method uses the characteristics of a combo box to create localized strings, while keeping the ability to process the selection using <code>string</code> identification.</p> <pre lang="cs">class CultureCombo { public string name {get; set;} public string display {get; set;} }</pre> <p>Next, you would incorporate the method that processes the array. Using this code, you can then apply that to the combo box.</p> <pre lang="cs">private List&lt;CultureCombo&gt; comboList(string[] termList) { List&lt;CultureCombo&gt; options = new List&lt;CultureCombo&gt;(); foreach (string word in termList) options.Add(new CultureCombo { name = word, display = rm.GetString(word) }); return options; }</pre> <p>The code assumes you have created a <code>ResourceManager</code> called <code>rm</code>. Replace <code>rm</code> above with whatever variable you used for the <code>ResourceManager</code>. In my code, it is represented with the code.</p> <pre lang="cs">Assembly myAssembly = typeof(Utilities).Assembly; ResourceManager rm = new ResourceManager("Hoot.Resources.Strings", myAssembly)</pre> <h2>Implementation</h2> <p>The first step to using this in a program is to create an array of <code>string</code> IDs, the <code>string</code> used to access the culture's translation. If you have incorporated localized <code>string</code>s, you would already have these. In my example:</p> <pre lang="cs">string[] special = { "Select", "Vowels", "DoubleI", "DoubleU", "NoVowels", "Consonants", "QNotU", "Palins", "HighFives", "HighFours", "NoHooks"};</pre> <p>Next, use the method to populate the combo box.</p> <pre lang="cs">searchOptions = comboList(special); cboSearch.ValueMember = "name"; cboSearch.DisplayMember = "display"; cboSearch.DataSource = searchOptions;</pre> <p>Finally, find the item in the list by looking at the <code>value</code> (or "<code>name</code>") of the combo box item:</p> <pre lang="cs">switch (cboSearch.SelectedValue.ToString()) { case "Vowels": btnVowelHeavy_Click(sender, e); break; case "Consonants": btnConsonantDumps_Click(sender, e); break; .. }</pre> <p>While the <code>string</code> presented in the combo box could be "<code>Vowels</code>", or "<code>Voyelles</code>" depending on the language, the value is the constant "<code>Vowels</code>".</p> <h2>Points of Interest</h2> <p>Combo boxes have a <code>DataSource</code> field, so you can use many different sources to populate the box. They also have separate fields for identifying the option chosen. You can use the <code>SelectedIndex</code>, as well as the <code>SelectedText</code> or <code>SelectedValue</code>. You determine what each represents by modifying the <code>DisplayMember</code> or <code>ValueMember</code> field.</p> <p>List boxes are very similar having the same <code>DataSource</code>, <code>DisplayMember</code>, and <code>ValueMember</code>. You can also change each of them programmatically.</p> <p>This code is from the program <a title="Hoot" href="/hoot/" target="_blank">Hoot</a>, a word game study tool I created for Scrabble and Words with Friends players.</p><div class="item_footer"><p><small><a href="https://tylerhosting.com/b2e/dbell.php/managing-localization-in-combo-boxes">Original post</a> blogged on <a href="http://www.tylerhosting.com/b2e/">Switched Keys</a>.</small></p></div>
Introduction

This example combines the use of combo boxes, a separate DataSource, and localized strings for alternate cultures.

Background

Using a combo box, programmers can use a selected item as a variable or parameter within a single method. In other cases, the combo box is a collection of options, each of which executes a different method. The combo box can be populated within the design, or assigned using a DataSource. Even a simple string array can be used for that. Processing the selection from the combo box when executing a different method for each combo box entry can be done using the index of the selected item.

string[] special = { "Select", "Vowels", "DoubleI", 
"DoubleU", "NoVowels", "Consonants", "QNotU", 
    "Palins", "HighFives", "HighFours", "NoHooks"};

cboSearch.DataSource = special;

switch (cboSearch.SelectedIndex) {

case 1: btnVowelHeavy_Click(sender, e); break;
        
... 

case 5: btnConsonantDumps_Click(sender, e); break;

...
}

An Alternate

When using the combo box selected index the routine may have to be modified each time a new item is added or items are moved around. If we add an item to the middle of the list, we have to figure out what the item number will be and then change the select statement. Case 2 may be the new one, so the original case 2 has to be changed to case 3, case 3 to case 4, etc.

To avoid that, it is possible to use the selected item's content. Using the actual string in the collection is often a clearer way to code.

switch(cboSearch.SelectedText) {
    case "Vowels": ...

Thus, case 1 would be replaced with case "Vowels". Additions to the collection will not require any reordering.

The Challenge

This works well until you have to support localization, that is, present different collections of strings based on the language selected. The string used in a switch statement must be a constant, so you can't use:

switch (cboSearch.SelectedText) {
    case rm.GetString("Vowels"): ...

We could go back to using indexes, but we want to avoid going back to that. This is where the CultureCombo comes in handy. This simple class and the supporting method uses the characteristics of a combo box to create localized strings, while keeping the ability to process the selection using string identification.

class CultureCombo
{
    public string name {get; set;}
    public string display {get; set;}
}

Next, you would incorporate the method that processes the array. Using this code, you can then apply that to the combo box.

private List<CultureCombo> comboList(string[] termList)
{
    List<CultureCombo> options = new List<CultureCombo>();
    foreach (string word in termList)
        options.Add(new CultureCombo { name = word, display = rm.GetString(word) });
    return options;         
}

The code assumes you have created a ResourceManager called rm. Replace rm above with whatever variable you used for the ResourceManager. In my code, it is represented with the code.

Assembly myAssembly = typeof(Utilities).Assembly;
ResourceManager rm = new ResourceManager("Hoot.Resources.Strings", myAssembly)

Implementation

The first step to using this in a program is to create an array of string IDs, the string used to access the culture's translation. If you have incorporated localized strings, you would already have these. In my example:

string[] special = { "Select", "Vowels", 
"DoubleI", "DoubleU", "NoVowels", "Consonants",
                "QNotU", "Palins", 
                "HighFives", "HighFours", "NoHooks"};

Next, use the method to populate the combo box.

searchOptions = comboList(special);
cboSearch.ValueMember = "name";
cboSearch.DisplayMember = "display";
cboSearch.DataSource = searchOptions;

Finally, find the item in the list by looking at the value (or "name") of the combo box item:

switch (cboSearch.SelectedValue.ToString())
{
    case "Vowels":
        btnVowelHeavy_Click(sender, e);
        break;
    case "Consonants":
        btnConsonantDumps_Click(sender, e);
        break;
..
}

While the string presented in the combo box could be "Vowels", or "Voyelles" depending on the language, the value is the constant "Vowels".

Points of Interest

Combo boxes have a DataSource field, so you can use many different sources to populate the box. They also have separate fields for identifying the option chosen. You can use the SelectedIndex, as well as the SelectedText or SelectedValue. You determine what each represents by modifying the DisplayMember or ValueMember field.

List boxes are very similar having the same DataSource, DisplayMember, and ValueMember. You can also change each of them programmatically.

This code is from the program Hoot, a word game study tool I created for Scrabble and Words with Friends players.

]]>
https://tylerhosting.com/b2e/dbell.php/managing-localization-in-combo-boxes#comments https://tylerhosting.com/b2e/dbell.php?tempskin=_rss2&disp=comments&p=377
Best Hoot Features https://tylerhosting.com/b2e/dbell.php/best-hoot-features Mon, 28 Nov 2016 16:01:00 +0000 Dana Bell Computing Scrabble 376@https://tylerhosting.com/b2e/
Deprecated: Creation of dynamic property Item::$cache_has_content_parts is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 4911

Deprecated: Creation of dynamic property Item::$renderers_validated is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 11107

Deprecated: Creation of dynamic property Item::$pages is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 2412

Deprecated: Creation of dynamic property ItemSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121
<p>It's been about five months since I started developing Hoot and I'm reviewing what I've accomplished and what I need to work on next. With the release of version 1.6.7 I am weighing the most useful features in Hoot. By the way, Hoot is a freely available Scrabble<sup>TM</sup> / word game study tool. Some might use it as a cheat in online games like Words with Friends but it's greatest value is as a study tool. Read about it and download on the <a title="Hoot" href="/hoot/" target="_blank">Hoot</a> website.</p> <h3>Combination Search </h3> <p>The latest addition to Hoot is the combination search screen. With this screen you can select one of several searches and then filter the search based on other options. This was inspired in part by the app Scrabble Expert Pro, and expanded to include the filters.</p> <p style="float: right; margin-left: 10px; width: 45%;"><a title="Combination Search" href="/b2e/media/blogs/dbell/combination.png"><img src="/b2e/media/blogs/dbell/combination.png" alt="Combination Search" width="100%" /></a></p> <p>The searches include Letter Count, Contains, Contains All, Prefix, Suffix, Anagrams, Sub-anagrams, Blank Anagrams, Super Anagrams, Extensions, Subwords, Hooks, Anagram Hooks, and a Pattern search. In comparing with other search tools, the terminology can be confusing. For example, the Word Builder in Scrabble Expert is the same as sub-anagrams where only words consisting of some letters in the search box are shown. The Contains All Letters is the same as super anagrams where all of the letters are used along with other letters.</p> <p>The filters include minimum and maximum word length, prefixes, suffixes, and a filter rack of available letters. After doing a primary search, you can continually edit and apply the rack filter to the primary results more quickly. Like most Hoot search screens, the list has a context menu (with the addition of definitions, if installed). There is also a convenient button to clear everything, and another beside it to open a new window of the same ilk.</p> <h3>Most useful features</h3> <h4>Subject Lists</h4> <p>Although not the MOST useful feature, subject lists in Hoot are probably the most unique. Previously  I called them named searches. Many players and clubs publish lists of words on a given subject for many different lexicons and publish them as text files, webpages, or PDF downloads. The hassle there is using lists from different lexicons, and finding the lists for your choice lexicon. Hoot makes that easy by enabling you to store lists in the database and studying those lists without worrying about the lexicon. Hoot only shows the words in the list that are valid in the selected lexicon.</p> <p>For example, you could use the list of bread terms at <a href="http://www.absp.org.uk/words/foodbread.shtml" target="_blank">http://www.absp.org.uk/words/foodbread.shtml</a> for the CSW15 list, and when viewing OWL3, you only see valid words in that one. In CSW15 there are about 110 valid words. In OWL3, only about 80 of them are valid, and in Words with Friends there's only 60 good words. </p> <p>Of course, one of the features of the Subject list editor is that you can add other words later. I added several, and viewing the slide show I saw more words and variations that could have been added, including WHITE, WHEAT, RYE, GINGERBREAD, READBASKET, CRISPBREADS, BREADFRUIT<br />SHORTBREAD, SWEETBREAD, SHOWBREAD, plus the plural of most words.</p> <h4>Slide show</h4> <p style="float: right; margin-left: 10px; width: 45%;"><a title="Slide Show" href="/b2e/media/blogs/dbell/b2eryess.png"><img src="/b2e/media/blogs/dbell/b2eryess.png" alt="Slide Show" width="100%" /></a></p> <p>Slide shows are not only useful, the impetous for choosing to develop Hoot was the lack of slide shows in current tools resembling Lexpert's slide shows. With the slide show you can study this or some other list, one word at a time, on a timer, or not. You can also study each word along with some related words, such as hooks, anagrams, and extensions. So while I am studying the term RYE, I notice that you can make it plural, or extend it both ways to form CRYER, DRYER, FRYER, PRYER, WRYER, and pluralize and extend some of those words.</p> <p>There is standard navigation through the list, four sorting options, and the ability to jump to any word. You can also flag words that you already know so you don't have to see them every time you study a certain list. An alternate list display shows the hooks for the subsearch. And finally, there is a tiny slide show that shows only the word in a small, resizable, window with the same navigation and sorting options. Of course, the slide show is available in all searches, not just subject lists.</p> <h4>Pardon My French</h4> <p style="float: right; margin-left: 10px; width: 30%;"><a href="/b2e/media/blogs/dbell/b2eopening-fr.png"><img src="/b2e/media/blogs/dbell/b2eopening-fr.png" alt="Pardon My French" width="100%" /></a></p> <p>Of course, subject lists, related words, and other features of a study tool assume you are using the same language and locale. The same word may have two different meanings in different languages and words in different languages are modified differently. Speaking of which, Hoot now has a French language option. The search features don't support French pecularities but you can add Subject lists for French categories, or change the prefixes and suffixes to support French word study. If you're playing in French you may want to download the <a title="ODS5" href="/hoot/downloads/ODS5.zip">ODS lexicon</a> or use a later version. Hoot can actually support both English and French using different databases. You can save the ODS lexicon in one database with the modified prefixes and suffuxes, and use the original English in another.</p> <p>Incidentally, I'm not a French speaker, so the translations may not be the best. Many of them were generated from the Visual Studio tool I often use. You might get a laugh out of some of them, but afterward let me know how terms would best be translated.</p> <h4>Definitions</h4> <p>One of the most recent additions to Hoot is definitions for words up to about 10 characters. As with the initial development of Lexicon creation the function is limited. The definitions are add only, so you can't delete or edit them without opening it with Microsoft Access. I've incorporated the definitions in two places so far, accompanying the slide show, and in the context menu in Combination Searches. The definitions were  generously provided by Mike Wolfberg, the author of <a title="WHAT" href="http://www.wolfberg.net/what/" target="_blank">WHAT</a>. </p> <h4>Scrabble Font</h4> <p style="float: right; margin-left: 10px; width: 45%;"><a title="Tile Board" href="/b2e/media/blogs/dbell/tileboard.png"><img src="/b2e/media/blogs/dbell/tileboard.png" alt="Tile Board" width="100%" /></a></p> <p>As is often the case, the development of Hoot required me to go into areas beyond the actual coding. In addition to the webpages for the program, and the help file I developed independently, I also had to design a font to be used with the program. I decided on a font instead of using tile images because they are much easier to resize, and otherwise manipulate. I started using Scramble as the tile font until I discovered it had to be licensed. NuTiles was developed using the outline of a different font available for free use. I simply resized the images and combined it with a background.The latest version of the font displays the characters using uppercase, and provides a blank tile when using a question mark. The tile values are those of Scrabble<sup>TM</sup>.</p> <p>NuTiles can also be used in the text reproduction of tile boards. Simple type the letters, or '?', and color the tile appropriately. Future versions should add DL, DW, TL, and TW for the bonus tiles. This is without spacing. You can add line-spacing or character spacing as desired. It is available as a separate <a title="download NuTiles" href="/hoot/downloads/NuTiles11.zip">download</a>. Like most fonts, it is only available in a single color format. You select the color (any color) to use and the letter and numbers in the font use the background color.</p> <h4>Highlights Only</h4> <p>Don't be mislead. All of these are just highlights and new features. There are many other features of Hoot that might interest you. Read about Hoot in the on-line <a title="Hoot Help" href="/hoot/help/" target="_blank">help</a> pages. The very latest features (like the Combination search) may not be discussed yet, but they will eventually make it to the help file. And, yes, Hoot is freely available to download and share.</p><div class="item_footer"><p><small><a href="https://tylerhosting.com/b2e/dbell.php/best-hoot-features">Original post</a> blogged on <a href="http://www.tylerhosting.com/b2e/">Switched Keys</a>.</small></p></div>
It's been about five months since I started developing Hoot and I'm reviewing what I've accomplished and what I need to work on next. With the release of version 1.6.7 I am weighing the most useful features in Hoot. By the way, Hoot is a freely available ScrabbleTM / word game study tool. Some might use it as a cheat in online games like Words with Friends but it's greatest value is as a study tool. Read about it and download on the Hoot website.

Combination Search 

The latest addition to Hoot is the combination search screen. With this screen you can select one of several searches and then filter the search based on other options. This was inspired in part by the app Scrabble Expert Pro, and expanded to include the filters.

Combination Search

The searches include Letter Count, Contains, Contains All, Prefix, Suffix, Anagrams, Sub-anagrams, Blank Anagrams, Super Anagrams, Extensions, Subwords, Hooks, Anagram Hooks, and a Pattern search. In comparing with other search tools, the terminology can be confusing. For example, the Word Builder in Scrabble Expert is the same as sub-anagrams where only words consisting of some letters in the search box are shown. The Contains All Letters is the same as super anagrams where all of the letters are used along with other letters.

The filters include minimum and maximum word length, prefixes, suffixes, and a filter rack of available letters. After doing a primary search, you can continually edit and apply the rack filter to the primary results more quickly. Like most Hoot search screens, the list has a context menu (with the addition of definitions, if installed). There is also a convenient button to clear everything, and another beside it to open a new window of the same ilk.

Most useful features

Subject Lists

Although not the MOST useful feature, subject lists in Hoot are probably the most unique. Previously  I called them named searches. Many players and clubs publish lists of words on a given subject for many different lexicons and publish them as text files, webpages, or PDF downloads. The hassle there is using lists from different lexicons, and finding the lists for your choice lexicon. Hoot makes that easy by enabling you to store lists in the database and studying those lists without worrying about the lexicon. Hoot only shows the words in the list that are valid in the selected lexicon.

For example, you could use the list of bread terms at http://www.absp.org.uk/words/foodbread.shtml for the CSW15 list, and when viewing OWL3, you only see valid words in that one. In CSW15 there are about 110 valid words. In OWL3, only about 80 of them are valid, and in Words with Friends there's only 60 good words. 

Of course, one of the features of the Subject list editor is that you can add other words later. I added several, and viewing the slide show I saw more words and variations that could have been added, including WHITE, WHEAT, RYE, GINGERBREAD, READBASKET, CRISPBREADS, BREADFRUIT
SHORTBREAD, SWEETBREAD, SHOWBREAD, plus the plural of most words.

Slide show

Slide Show

Slide shows are not only useful, the impetous for choosing to develop Hoot was the lack of slide shows in current tools resembling Lexpert's slide shows. With the slide show you can study this or some other list, one word at a time, on a timer, or not. You can also study each word along with some related words, such as hooks, anagrams, and extensions. So while I am studying the term RYE, I notice that you can make it plural, or extend it both ways to form CRYER, DRYER, FRYER, PRYER, WRYER, and pluralize and extend some of those words.

There is standard navigation through the list, four sorting options, and the ability to jump to any word. You can also flag words that you already know so you don't have to see them every time you study a certain list. An alternate list display shows the hooks for the subsearch. And finally, there is a tiny slide show that shows only the word in a small, resizable, window with the same navigation and sorting options. Of course, the slide show is available in all searches, not just subject lists.

Pardon My French

Pardon My French

Of course, subject lists, related words, and other features of a study tool assume you are using the same language and locale. The same word may have two different meanings in different languages and words in different languages are modified differently. Speaking of which, Hoot now has a French language option. The search features don't support French pecularities but you can add Subject lists for French categories, or change the prefixes and suffixes to support French word study. If you're playing in French you may want to download the ODS lexicon or use a later version. Hoot can actually support both English and French using different databases. You can save the ODS lexicon in one database with the modified prefixes and suffuxes, and use the original English in another.

Incidentally, I'm not a French speaker, so the translations may not be the best. Many of them were generated from the Visual Studio tool I often use. You might get a laugh out of some of them, but afterward let me know how terms would best be translated.

Definitions

One of the most recent additions to Hoot is definitions for words up to about 10 characters. As with the initial development of Lexicon creation the function is limited. The definitions are add only, so you can't delete or edit them without opening it with Microsoft Access. I've incorporated the definitions in two places so far, accompanying the slide show, and in the context menu in Combination Searches. The definitions were  generously provided by Mike Wolfberg, the author of WHAT

Scrabble Font

Tile Board

As is often the case, the development of Hoot required me to go into areas beyond the actual coding. In addition to the webpages for the program, and the help file I developed independently, I also had to design a font to be used with the program. I decided on a font instead of using tile images because they are much easier to resize, and otherwise manipulate. I started using Scramble as the tile font until I discovered it had to be licensed. NuTiles was developed using the outline of a different font available for free use. I simply resized the images and combined it with a background.The latest version of the font displays the characters using uppercase, and provides a blank tile when using a question mark. The tile values are those of ScrabbleTM.

NuTiles can also be used in the text reproduction of tile boards. Simple type the letters, or '?', and color the tile appropriately. Future versions should add DL, DW, TL, and TW for the bonus tiles. This is without spacing. You can add line-spacing or character spacing as desired. It is available as a separate download. Like most fonts, it is only available in a single color format. You select the color (any color) to use and the letter and numbers in the font use the background color.

Highlights Only

Don't be mislead. All of these are just highlights and new features. There are many other features of Hoot that might interest you. Read about Hoot in the on-line help pages. The very latest features (like the Combination search) may not be discussed yet, but they will eventually make it to the help file. And, yes, Hoot is freely available to download and share.

]]>
https://tylerhosting.com/b2e/dbell.php/best-hoot-features#comments https://tylerhosting.com/b2e/dbell.php?tempskin=_rss2&disp=comments&p=376
Behind the AOTC Worksheet https://tylerhosting.com/b2e/dbell.php/behind-the-aotc-worksheet Sun, 01 Feb 2015 17:25:00 +0000 Dana Bell Information Technology Computing Professional 346@https://tylerhosting.com/b2e/
Deprecated: Creation of dynamic property Item::$cache_has_content_parts is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 4911

Deprecated: Creation of dynamic property Item::$renderers_validated is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 11107

Deprecated: Creation of dynamic property Item::$pages is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 2412

Deprecated: Creation of dynamic property ItemSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121
<h2>Introduction</h2> <p><strong>Note: This is an IT article, not a tax article.</strong></p> <p>As a part of a campaign to increase awareness of education tax credits I created an AOTC worksheet. The Excel version of the worksheet is demonstrated in my article <a href="/b2e/dbell.php/amending-for-education-credits-1">Amending for Education Credits</a>  and includes the simple formulas being used. There is also a <a href="/b2e/media/blogs/dbell/aotc%20worksheet.pdf">PDF version</a> of the spreadsheet that I’ve made available for download and it calculates the values based on the four entries you make.<a href="/b2e/media/blogs/dbell/aotccompleted.png?mtime=1422810986"><img style="float: right; border: 1px solid black; margin: 10px;" src="/b2e/media/blogs/dbell/aotccompleted.png?mtime=1422810986" alt="Completed AOTC Worksheet" width="350" /></a></p> <p>Creating such a worksheet begins with a simple export of a Word document to PDF. Adding the calculation logic of the worksheet requires a little more work and a full version of Adobe Acrobat. Using it only requires the Acrobat Reader.</p> <p>The process used to tap into a PDF’s intelligence can be used to create other files that can help clients, users, members, or staff do similar calculations without the need to have or use spreadsheet software. Of course, it is not an Excel replacement, but there are cases, as here, where it can be quite handy. Acrobat has many other abilities that could be integrated in the workflow of a professional office as well.</p> <h2>Create Document</h2> <p>The first thing that I do is create a document and add the table that calculates the AOTC. I started this in Word and then printed to a PDF file. You may also be able to save or export to a PDF. You should make sure the formatting and alignment is the way you want it because it’s difficult to impossible to make major changes in a PDF. Modifying the form for user form-filling will require you to set fields and add calculations. There are 12 fields in this worksheet but the form has only four fields the user needs to enter information into and they have been highlighted with a wider border.</p> <h2>Open PDF</h2> <p>If the PDF doesn’t open automatically, open it with Adobe Acrobat.</p> <h2>Add/Edit Fields</h2> <p>With the PDF open, select Forms on the menu and then Add or Edit Fields…</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/formsmenu.png?mtime=1422203431"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/formsmenu.png?mtime=1422203431" alt="" width="195" height="100" /></a></div> <h2>Detect fields</h2> <p>Acrobat makes it easy by offering to detect possible form fields in the document. You can manually add other form fields if you need to. Select Yes.</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/detectfields.png?mtime=1422203431"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/detectfields.png?mtime=1422203431" alt="" width="499" height="168" /></a></div> <p>With fields detected and added the form will look like this.</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/aotcautofields.png?mtime=1422203427"><img style="border: 1px solid black; display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/aotcautofields.png?mtime=1422203427" alt="" width="548" height="479" /></a></div> <p>Once all the fields are added, you could allow users to make all their own calculations. The instructions are there but the purpose of this guide is to show how to let Acrobat make the calculations for the user. For that you will need to name the fields and add code to make the calculations.</p> <h2>Name fields</h2> <p>The name of each field comes from the adjoining text. A few fields may be added that will not be used, such as the Line 4 Taxable Scholarships. Clicking on any field will make it active and highlighted in blue. You can then delete or edit the field properties. For the Taxable Scholarships field in the left column I simply click and delete. Then I rename the other fields.</p> <p>Right click on the field and select the menu option to Rename fields, and enter a short meaningful name for the field. Do that for all fields to be used.</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/rename.png?mtime=1422203424"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/rename.png?mtime=1422203424" alt="" width="250" height="71" /></a></div> <p>The following shows all fields renamed for my form.</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/aotcfields.png?mtime=1422203430"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/aotcfields.png?mtime=1422203430" alt="" width="553" height="486" /></a></div> <h2>Properties</h2> <p>You can also right click and edit properties. From this menu you can rename the field, add any tooltips and set other properties. For the line 10 properties, I’ve added the tooltip text shown. It is best to rename all the fields before going further since the formulas will use the names assigned.</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/genproperties.png?mtime=1422203424"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/genproperties.png?mtime=1422203424" alt="" width="472" height="388" /></a></div> <div class="image_block"> </div> <div class="image_block">Properties is also where you can change the formatting of the entry. The default sets the font size based on the height of the entry box. Depending on the size of the field you may want to change the font size and style. Other tabs allow you to apply formatting, such as for number fields or alignment.</div> <div class="image_block"> </div> <div class="image_block"> <div class="image_block"><a href="/b2e/media/blogs/dbell/propsappearance.png?mtime=1422653985"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/propsappearance.png?mtime=1422653985" alt="" width="472" height="435" /></a></div> </div> <h2>Add formulas.</h2> <p>After all the fields have been renamed, for each field, go to the properties again (right click). Select the end tab labeled Calculate. This is where you enter the formulas needed to make the calculations. All of the formulas in this form use a custom calculation script in the Javascript language. Javascript is a popular language for web pages. The scripts here are basic with limited syntax. With a little study you should be able to determine how to assign variables, add, subtract, and use conditionals (if statements). </p> <div class="image_block"><a href="/b2e/media/blogs/dbell/calcproperties.png?mtime=1422203430"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/calcproperties.png?mtime=1422203430" alt="" width="472" height="493" /></a></div> <p>In order to edit the script, click the Edit button to the right of the selected box. Following is the script for line 10 (AOTCQualExp). The script gets the value from line 1 and then determines the appropriate value for this line. In pseudocode this says</p> <p><em>If the value in line 1 (field named QualExp) is greater than 4000, then the value in this field is 4000, otherwise this value is the same as the value of QualExp.</em></p> <div class="image_block"><a href="/b2e/media/blogs/dbell/javascripteditor.png?mtime=1422203424"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/javascripteditor.png?mtime=1422203424" alt="JavaScript Editor" width="600" /></a></div> <h2>Reference</h2> <p>When you have finished adding all the scripts you can see them in a single document from the Advanced menu in Acrobat. Select document processing and then Edit All Javascripts.</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/advanced.png?mtime=1422203425"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/advanced.png?mtime=1422203425" alt="" width="273" height="282" /></a></div> <div class="image_block"> </div> <h2><a href="/b2e/media/blogs/dbell/advdocproc.png?mtime=1422203425"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/advdocproc.png?mtime=1422203425" alt="" width="226" height="348" /></a></h2> <h2>Set Read-Only</h2> <p>Remember that the user only enters values in four of the fields in this form, with the rest being self-calculating. For fields that do not require user input, set the Read-Only attribute. This is done by checking the Read-Only box in the first tab under Properties.</p> <div class="image_block"><a href="/b2e/media/blogs/dbell/genproperties.png?mtime=1422203424"><img style="display: block; margin-left: auto; margin-right: auto;" src="/b2e/media/blogs/dbell/genproperties.png?mtime=1422203424" alt="" width="472" height="388" /></a></div> <h2>Clear button</h2> <p>In order to simplify the use of the form you can also add a button to clear the form. To do this, go to</p> <ul> <li>Tools &gt; Advanced Editing &gt; Button, and draw out a box that can be click to clear the form. Name it.</li> <li>Right click for Properties &gt; Actions, and select the action to Reset a form.</li> <li>Properties &gt; Options &gt; Label, and enter the text to be displayed on the form.</li> </ul> <p>Save!</p> <h2>Test and Re-test</h2> <p>The only thing left to do now is test and re-test the form calculations and make corrections where needed. When you are pleased with your work, save, backup, and distribute the form.</p><div class="item_footer"><p><small><a href="https://tylerhosting.com/b2e/dbell.php/behind-the-aotc-worksheet">Original post</a> blogged on <a href="http://www.tylerhosting.com/b2e/">Switched Keys</a>.</small></p></div>
Introduction

Note: This is an IT article, not a tax article.

As a part of a campaign to increase awareness of education tax credits I created an AOTC worksheet. The Excel version of the worksheet is demonstrated in my article Amending for Education Credits  and includes the simple formulas being used. There is also a PDF version of the spreadsheet that I’ve made available for download and it calculates the values based on the four entries you make.Completed AOTC Worksheet

Creating such a worksheet begins with a simple export of a Word document to PDF. Adding the calculation logic of the worksheet requires a little more work and a full version of Adobe Acrobat. Using it only requires the Acrobat Reader.

The process used to tap into a PDF’s intelligence can be used to create other files that can help clients, users, members, or staff do similar calculations without the need to have or use spreadsheet software. Of course, it is not an Excel replacement, but there are cases, as here, where it can be quite handy. Acrobat has many other abilities that could be integrated in the workflow of a professional office as well.

Create Document

The first thing that I do is create a document and add the table that calculates the AOTC. I started this in Word and then printed to a PDF file. You may also be able to save or export to a PDF. You should make sure the formatting and alignment is the way you want it because it’s difficult to impossible to make major changes in a PDF. Modifying the form for user form-filling will require you to set fields and add calculations. There are 12 fields in this worksheet but the form has only four fields the user needs to enter information into and they have been highlighted with a wider border.

Open PDF

If the PDF doesn’t open automatically, open it with Adobe Acrobat.

Add/Edit Fields

With the PDF open, select Forms on the menu and then Add or Edit Fields…

Detect fields

Acrobat makes it easy by offering to detect possible form fields in the document. You can manually add other form fields if you need to. Select Yes.

With fields detected and added the form will look like this.

Once all the fields are added, you could allow users to make all their own calculations. The instructions are there but the purpose of this guide is to show how to let Acrobat make the calculations for the user. For that you will need to name the fields and add code to make the calculations.

Name fields

The name of each field comes from the adjoining text. A few fields may be added that will not be used, such as the Line 4 Taxable Scholarships. Clicking on any field will make it active and highlighted in blue. You can then delete or edit the field properties. For the Taxable Scholarships field in the left column I simply click and delete. Then I rename the other fields.

Right click on the field and select the menu option to Rename fields, and enter a short meaningful name for the field. Do that for all fields to be used.

The following shows all fields renamed for my form.

Properties

You can also right click and edit properties. From this menu you can rename the field, add any tooltips and set other properties. For the line 10 properties, I’ve added the tooltip text shown. It is best to rename all the fields before going further since the formulas will use the names assigned.

 
Properties is also where you can change the formatting of the entry. The default sets the font size based on the height of the entry box. Depending on the size of the field you may want to change the font size and style. Other tabs allow you to apply formatting, such as for number fields or alignment.
 

Add formulas.

After all the fields have been renamed, for each field, go to the properties again (right click). Select the end tab labeled Calculate. This is where you enter the formulas needed to make the calculations. All of the formulas in this form use a custom calculation script in the Javascript language. Javascript is a popular language for web pages. The scripts here are basic with limited syntax. With a little study you should be able to determine how to assign variables, add, subtract, and use conditionals (if statements). 

In order to edit the script, click the Edit button to the right of the selected box. Following is the script for line 10 (AOTCQualExp). The script gets the value from line 1 and then determines the appropriate value for this line. In pseudocode this says

If the value in line 1 (field named QualExp) is greater than 4000, then the value in this field is 4000, otherwise this value is the same as the value of QualExp.

JavaScript Editor

Reference

When you have finished adding all the scripts you can see them in a single document from the Advanced menu in Acrobat. Select document processing and then Edit All Javascripts.

 

Set Read-Only

Remember that the user only enters values in four of the fields in this form, with the rest being self-calculating. For fields that do not require user input, set the Read-Only attribute. This is done by checking the Read-Only box in the first tab under Properties.

Clear button

In order to simplify the use of the form you can also add a button to clear the form. To do this, go to

  • Tools > Advanced Editing > Button, and draw out a box that can be click to clear the form. Name it.
  • Right click for Properties > Actions, and select the action to Reset a form.
  • Properties > Options > Label, and enter the text to be displayed on the form.

Save!

Test and Re-test

The only thing left to do now is test and re-test the form calculations and make corrections where needed. When you are pleased with your work, save, backup, and distribute the form.

]]>
https://tylerhosting.com/b2e/dbell.php/behind-the-aotc-worksheet#comments https://tylerhosting.com/b2e/dbell.php?tempskin=_rss2&disp=comments&p=346
External Table Data in Access https://tylerhosting.com/b2e/dbell.php/external-table-data-in-access Fri, 03 Oct 2014 21:01:00 +0000 Dana Bell Information Technology Computing Professional Microsoft Office Access 334@https://tylerhosting.com/b2e/
Deprecated: Creation of dynamic property Item::$cache_has_content_parts is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 4911

Deprecated: Creation of dynamic property Item::$renderers_validated is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 11107

Deprecated: Creation of dynamic property Item::$pages is deprecated in /home4/tylering/public_html/b2e/inc/items/model/_item.class.php on line 2412

Deprecated: Creation of dynamic property ItemSettings::$count_col_key_names is deprecated in /home4/tylering/public_html/b2e/inc/settings/model/_abstractsettings.class.php on line 121
<p>I'm constantly coming up with new ideas for projects, articles, and ways to do things. One way I tried to keep up with that was to create text files with those notes. Many years ago I used Microsoft's cardfile.exe but it no longer exists in current versions of Windows. Then, a few years ago I tried out the AZZ Cardfile program. Shortly after that I created my own card file database similar to AZZ Cardfile, named simply <strong><em>Simple Cards</em></strong>. The cards are listed by title on the left and the content of the selected card shows in the middle content area. The cards are categorized, sortable, and searchable. In order to make the application work I had to develop a number of routines to make sure the list and cards were synchronized, including when searching and filtering, when adding or deleting cards, and when resorting. Work still needs to be done to smooth the transitions between screens, being able to select and delete multiple cards, and exporting a category of cards to an external file. A programmer's work never ends.</p> <p>As in AZZ, you can also create external data files of cards in Simple Cards. The external files are actually separate databases. Ignoring the general development of Simple Cards for now, this article shows how to enable external table data in an Access program, first with an explanation and then some code samples.<br /><br />When Access displays a form, it relies on a source file for the data, either directly from a table, or from a query based on one or more tables. Typically, the only time Access uses an external table is if the database is split into front end/back end, but it is possible to access external data as a record source for a form or report, without technically splitting the database and creating links to external tables. The best way to do that is to use a query instead of a table as record source for a form.<br /><br />If the form is based on a query the tables are normally from within the database. However, if you open the query for editing and access the properties of the query, you can see that there is an option to specify the database to use under Source Database. If the query was created with internal tables, it will have "(current)" in gray. If you change that to refer to a different database, it will load data from that external file instead. After specifying an external database, you can view the SQL code for the query and notice that an additional qualifier, 'IN', is used in the query with the file path of the external file. <br /><br />In my project, however, I wanted the user to be able to optionally access one of several different databases for the form. So the user doesn't have to go to the query and enter a long file path to do this, Application.FileDialog is used to select the database. The problem is, outside of Microsoft, there is no direct way to change the Source Database of the query. I've searched, and asked, and searched, and I cannot find a way to access those properties. In order to change that, you have to change the SQL property of the query. To load an external file, you have to build the SQL statement; and to read the filespec of a loaded file, you have to search the SQL statement. <br /><br />In developing Simple Cards I also had to incorporate some user messages so the user would know what file is being used. In addition, I change the caption to show the file being used if it's an external file, both when loading external files, and when restarting with an external file. Finally, in order to make this work with less confusion for the user, instead of saving external databases with the normal extension, I used the "crd" extension. Access doesn't care, and the files won't be associated with Access.<br /><br />Following are the steps I took to enable this feature.</p> <p>First, I create the form to open the data using a query (qryCardFile) so I can change the query in order to change data source. On the main form is a button that enables the user to open an external file, with the following code to change the SQL statement.</p> <div style="font-family: courier new,courier; color: #000000; background-color: #ffffff; padding: 10px;">Set db = CurrentDb<br />Set qdf = db.QueryDefs("qryCardFile")<br />    <br />FileSelected = modFileDialog()<br />qdf.SQL = "SELECT tblCardfile.CardID, tblCardfile.Title, tblCardfile.Content, tblCardfile.CardDate, tblCardfile.CardCategory, tblCardfile.ChangeDate " &amp; _<br />    "FROM tblCardfile <strong>IN '" &amp; FileSelected &amp; "'</strong> " &amp; _<br />    "ORDER BY tblCardfile.CardID;"<br />        <br />DoCmd.OpenForm "frmReopen", , , , , , FileSelected</div> <p>Notice that I change the query by adding IN and the name of the file selected. You will also notice that I use an extra parameter (FileSelected) in the OpenForm command. The extra parameter is OpenArgs which enables you to pass the filespec to the form open subroutine. And, of course, you notice that I use this to open a different form. Using form frmReopen is a tidy way to close and reopen the main form without confusion for the user.</p> <p>Following is the relevant code in frmReopen</p> <div style="font-family: courier new,courier; color: #000000; background-color: #ffffff; padding: 10px;">DoCmd.Close acForm, "frmCardFile"<br />Me.Visible = False<br />'Use timer to give form time to load<br />... <br />DoCmd.OpenForm "frmCardFile", , , , , , Me.OpenArgs<br />DoCmd.Close acForm, "frmReopen"</div> <p>This simply closes the main form and then reopens it with the new external data table. The change in the query's SQL in the prior code sample is what enables the loading of the external data. The Me.OpenArgs parameter is only used to update the form caption.</p> <p>Incidentally, this technique could be used to view the content of any external table since the query can use the global qualifier, although additional work is required to get a list of tables in that external database.</p> <p>The following code is what actually changes the caption</p> <div style="font-family: courier new,courier; color: #000000; background-color: #ffffff; padding: 10px;">If IsNull(Me.OpenArgs) Then<br />    source = GetSourceDB<br />    If (source = "tblCardFile") Then<br />        Me.Form.Caption = "Simple Cards"<br />    Else<br />        Me.Form.Caption = "Simple Cards from " &amp; source<br />        MsgBox ("Using external data from " &amp; source)<br />    End If<br />Else<br />    Me.Form.Caption = "Simple Cards from " &amp; Me.OpenArgs<br />    MsgBox ("Using external data from " &amp; Me.OpenArgs)<br />End If</div> <p>The following code (GetSourceDB) is what gets caption information from the SQL statement of the query</p> <div style="font-family: courier new,courier; color: #000000; background-color: #ffffff; padding: 10px;">sqlstatement = CurrentDb.QueryDefs("qryCardFile").Properties("SQL")<br />ending = InStr(sqlstatement, "ORDER")<br />starting = InStr(sqlstatement, "IN '")<br />If (starting = 0) Then<br /> source = "tblCardFile"<br />Else<br /> source = Mid(sqlstatement, starting + 4, (ending - 3) - (starting + 4))<br />End If<br />GetSourceDB = source</div> <p>If this code cannot find 'IN' in the query, then the query must be using the internal table.</p> <p>Of course, the user will not want to manually create external databases, so an option to create one is made available from a button on the form. This simple code snippet shows how to create a database and copy the structure of the CardFile table to that database. Then it uses a modified version of the ChangeCards subroutine to load that blank external file.</p> <div style="font-family: courier new,courier; color: #000000; background-color: #ffffff; padding: 10px;">CardFileName = modSaveAsDialog<br />   <br />'Make sure there isn't already a file with the name of the new database<br />...<br /><br />Set db = ws.CreateDatabase(CardFileName, dbLangGeneral)<br />DoCmd.TransferDatabase acExport, "Microsoft Access", CardFileName, acTable, "tblCardfile", "tblCardfile", True<br />db.Close<br />Set db = Nothing<br /><br />ChangeCards (CardFileName)</div> <p>While the whole concept of using external files may be hard to grasp at first, with a logical study of the flow of data and order of instructions in the code it's possible to create routines to do things like this and make it look simple.</p> <p>Note that you may have to set the relevant Office references for your version of Access in order to use the FileDialog routines. Some word-wrapping may have occurred in code sections presented but marking and copying usually preserves underlying formatting.</p> <p>P. S.</p> <p>One issue with using external database files in an application is that Microsoft Access processes queries before processing forms. As a result, if the query fails to load, the form fails to load. This could be due to an invalid card file, or a missing card file. In order to avoid this unpleasant situation, you have to error check (not shown in the code clippings above) for the file when loading the form. You can’t error check in the main form itself. In this case, the check is done in the Splash screen, or Reopen form, when it opens the main form.</p><div class="item_footer"><p><small><a href="https://tylerhosting.com/b2e/dbell.php/external-table-data-in-access">Original post</a> blogged on <a href="http://www.tylerhosting.com/b2e/">Switched Keys</a>.</small></p></div>
I'm constantly coming up with new ideas for projects, articles, and ways to do things. One way I tried to keep up with that was to create text files with those notes. Many years ago I used Microsoft's cardfile.exe but it no longer exists in current versions of Windows. Then, a few years ago I tried out the AZZ Cardfile program. Shortly after that I created my own card file database similar to AZZ Cardfile, named simply Simple Cards. The cards are listed by title on the left and the content of the selected card shows in the middle content area. The cards are categorized, sortable, and searchable. In order to make the application work I had to develop a number of routines to make sure the list and cards were synchronized, including when searching and filtering, when adding or deleting cards, and when resorting. Work still needs to be done to smooth the transitions between screens, being able to select and delete multiple cards, and exporting a category of cards to an external file. A programmer's work never ends.

As in AZZ, you can also create external data files of cards in Simple Cards. The external files are actually separate databases. Ignoring the general development of Simple Cards for now, this article shows how to enable external table data in an Access program, first with an explanation and then some code samples.

When Access displays a form, it relies on a source file for the data, either directly from a table, or from a query based on one or more tables. Typically, the only time Access uses an external table is if the database is split into front end/back end, but it is possible to access external data as a record source for a form or report, without technically splitting the database and creating links to external tables. The best way to do that is to use a query instead of a table as record source for a form.

If the form is based on a query the tables are normally from within the database. However, if you open the query for editing and access the properties of the query, you can see that there is an option to specify the database to use under Source Database. If the query was created with internal tables, it will have "(current)" in gray. If you change that to refer to a different database, it will load data from that external file instead. After specifying an external database, you can view the SQL code for the query and notice that an additional qualifier, 'IN', is used in the query with the file path of the external file.

In my project, however, I wanted the user to be able to optionally access one of several different databases for the form. So the user doesn't have to go to the query and enter a long file path to do this, Application.FileDialog is used to select the database. The problem is, outside of Microsoft, there is no direct way to change the Source Database of the query. I've searched, and asked, and searched, and I cannot find a way to access those properties. In order to change that, you have to change the SQL property of the query. To load an external file, you have to build the SQL statement; and to read the filespec of a loaded file, you have to search the SQL statement.

In developing Simple Cards I also had to incorporate some user messages so the user would know what file is being used. In addition, I change the caption to show the file being used if it's an external file, both when loading external files, and when restarting with an external file. Finally, in order to make this work with less confusion for the user, instead of saving external databases with the normal extension, I used the "crd" extension. Access doesn't care, and the files won't be associated with Access.

Following are the steps I took to enable this feature.

First, I create the form to open the data using a query (qryCardFile) so I can change the query in order to change data source. On the main form is a button that enables the user to open an external file, with the following code to change the SQL statement.

Set db = CurrentDb
Set qdf = db.QueryDefs("qryCardFile")
    
FileSelected = modFileDialog()
qdf.SQL = "SELECT tblCardfile.CardID, tblCardfile.Title, tblCardfile.Content, tblCardfile.CardDate, tblCardfile.CardCategory, tblCardfile.ChangeDate " & _
    "FROM tblCardfile IN '" & FileSelected & "' " & _
    "ORDER BY tblCardfile.CardID;"
        
DoCmd.OpenForm "frmReopen", , , , , , FileSelected

Notice that I change the query by adding IN and the name of the file selected. You will also notice that I use an extra parameter (FileSelected) in the OpenForm command. The extra parameter is OpenArgs which enables you to pass the filespec to the form open subroutine. And, of course, you notice that I use this to open a different form. Using form frmReopen is a tidy way to close and reopen the main form without confusion for the user.

Following is the relevant code in frmReopen

DoCmd.Close acForm, "frmCardFile"
Me.Visible = False
'Use timer to give form time to load
...
DoCmd.OpenForm "frmCardFile", , , , , , Me.OpenArgs
DoCmd.Close acForm, "frmReopen"

This simply closes the main form and then reopens it with the new external data table. The change in the query's SQL in the prior code sample is what enables the loading of the external data. The Me.OpenArgs parameter is only used to update the form caption.

Incidentally, this technique could be used to view the content of any external table since the query can use the global qualifier, although additional work is required to get a list of tables in that external database.

The following code is what actually changes the caption

If IsNull(Me.OpenArgs) Then
    source = GetSourceDB
    If (source = "tblCardFile") Then
        Me.Form.Caption = "Simple Cards"
    Else
        Me.Form.Caption = "Simple Cards from " & source
        MsgBox ("Using external data from " & source)
    End If
Else
    Me.Form.Caption = "Simple Cards from " & Me.OpenArgs
    MsgBox ("Using external data from " & Me.OpenArgs)
End If

The following code (GetSourceDB) is what gets caption information from the SQL statement of the query

sqlstatement = CurrentDb.QueryDefs("qryCardFile").Properties("SQL")
ending = InStr(sqlstatement, "ORDER")
starting = InStr(sqlstatement, "IN '")
If (starting = 0) Then
source = "tblCardFile"
Else
source = Mid(sqlstatement, starting + 4, (ending - 3) - (starting + 4))
End If
GetSourceDB = source

If this code cannot find 'IN' in the query, then the query must be using the internal table.

Of course, the user will not want to manually create external databases, so an option to create one is made available from a button on the form. This simple code snippet shows how to create a database and copy the structure of the CardFile table to that database. Then it uses a modified version of the ChangeCards subroutine to load that blank external file.

CardFileName = modSaveAsDialog
   
'Make sure there isn't already a file with the name of the new database
...

Set db = ws.CreateDatabase(CardFileName, dbLangGeneral)
DoCmd.TransferDatabase acExport, "Microsoft Access", CardFileName, acTable, "tblCardfile", "tblCardfile", True
db.Close
Set db = Nothing

ChangeCards (CardFileName)

While the whole concept of using external files may be hard to grasp at first, with a logical study of the flow of data and order of instructions in the code it's possible to create routines to do things like this and make it look simple.

Note that you may have to set the relevant Office references for your version of Access in order to use the FileDialog routines. Some word-wrapping may have occurred in code sections presented but marking and copying usually preserves underlying formatting.

P. S.

One issue with using external database files in an application is that Microsoft Access processes queries before processing forms. As a result, if the query fails to load, the form fails to load. This could be due to an invalid card file, or a missing card file. In order to avoid this unpleasant situation, you have to error check (not shown in the code clippings above) for the file when loading the form. You can’t error check in the main form itself. In this case, the check is done in the Splash screen, or Reopen form, when it opens the main form.

]]>
https://tylerhosting.com/b2e/dbell.php/external-table-data-in-access#comments https://tylerhosting.com/b2e/dbell.php?tempskin=_rss2&disp=comments&p=334

Deprecated: substr(): Passing null to parameter #1 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 932

Deprecated: substr(): Passing null to parameter #1 ($string) of type string is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 933

Deprecated: Creation of dynamic property Hit::$is_lynx is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 571

Deprecated: Creation of dynamic property Hit::$is_firefox is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 572

Deprecated: Creation of dynamic property Hit::$is_gecko is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 573

Deprecated: Creation of dynamic property Hit::$is_IE is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 574

Deprecated: Creation of dynamic property Hit::$is_winIE is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 575

Deprecated: Creation of dynamic property Hit::$is_macIE is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 576

Deprecated: Creation of dynamic property Hit::$is_chrome is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 577

Deprecated: Creation of dynamic property Hit::$is_safari is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 578

Deprecated: Creation of dynamic property Hit::$is_opera is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 579

Deprecated: Creation of dynamic property Hit::$is_NS4 is deprecated in /home4/tylering/public_html/b2e/inc/sessions/model/_hit.class.php on line 580