With rbx.lua, how do you edit GUI properties? - user-interface

Changing UI_ELEMENT.Visible to true, and then false shows and hides the UI element, however when I switch it to true again it doesn't reappear. I believe this may be an issue of how I'm doing it rather than what I'm doing.
Hi,
I'm new to Roblox Lua (But I have Javascript and C# experience). I am working on making a 'Garage' or 'Parts' GUI. I'm am trying to make a click detector on a text object set the UI_ELEMENT.Visible of a UI element to true. And a text button (Part of the previously mentions UI element) set that UI_ELEMENT.Visible back to false.
This process works fine until I run through it multiple times (e.g setting to true, then false, and then true again). The UI_ELEMENT.Visible is 'locked' at true (as in setting it to false just results in it being set back to true next frame) but the UI doesn't show.
Code:
click_detector1.MouseClick:connect(function(player) -- When clicked
_G.PlayerInfo[player.Name].status = "In Garage" -- set player status to in garage (works fine no issues)
_G.PlayerInfo[player.Name].topbar = "" -- reset topbar (works)
print("this is only supposed to happen once") -- a check to see if this is running more than once
game.Players[tostring(player.Name)].PlayerGui.Garage.menu.Visible = true -- one way that should work
--.Enabled = true -- another way that should work
--.menu.Position = UDim2.new(0.5, 0, 0,0) -- another way that should work (setting position to center of screen)
end)
The above is in a server script (let's call it script #1).
button = script.Parent
local function onButtonActivated()
local Players = game:GetService("Players")
local player = Players.LocalPlayer -- get the local player
print("I am only running once") -- test to see if this is running more than once
game.Players[tostring(player.Name)].PlayerGui.Garage.menu.Visible = false -- one way that should work
--.Enabled = false -- another way that should work
--.menu.Position = UDim2.new(10, 0, 0,0) -- another way that should work (change x scale to off screen)
end
button.Activated:Connect(onButtonActivated)
The above is in a local script (let's call this script #2).
The interesting thing is that none of the methods I proposed in the 'another way that should work' actually function more than the initial first cycle of the loop (e.g setting to true, then false, and then true again).
Also logging the tests to see if they run multiple times only runs once each time it is cycled through (Like it should). However, this means the code for setting it to visible is also running, but not logging an error or doing what it should do.
Thanks, Daniel Morgan

I believe the issue lies with your use of a server script and local script. LocalScripts only change what's on the player's client. Non-local scripts change whats on the server. In other words, non-local scripts affect everyone while LocalScripts only affect individual players.
Setting the visibility of the GUI to false through a LocalScript will only change the GUI on the player's client. However, the server will still see the player's GUI visibility as true. This discrepancy may be causing you issues.
I would suggest an alternative method using RemoteEvents. Instead of changing the GUI visibility to false in a LocalScript as you do in script #2, I would use a RemoteEvent to do that instead. In your case it would look something like the following:
The following is what would be in a non-local script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = Instance.new("RemoteEvent",ReplicatedStorage)
remoteEvent.Name = "MyRemoteEventName"
-- player is the player object, visibility is a boolean (true or false)
local function ChangeGuiVisibility(player, visibility)
player.PlayerGui.Garage.menu.Visible = visibility
end
-- Call "onCreatePart()" when the client fires the remote event
remoteEvent.OnServerEvent:Connect(onCreatePart)
You can Fire this remote event from a local script like this:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local visiblity = false
local remoteEvent = ReplicatedStorage:WaitForChild("MyRemoteEventName")
-- Fire the remote event.
remoteEvent:FireServer(visibility)-- NOTE: the player object is automatically passed in as the first argument to FireServer()
Here is a very good guide on RemoteEvents: https://developer.roblox.com/en-us/articles/Remote-Functions-and-Events
Basically, RemoteEvents allow you to bridge the gap between the client and server. The client can fire an event to which the server will respond to. A while ago, this was not the case with Roblox. Changes from the client were visible to the server, which made exploiting games very easy.
Also, I'd like to suggest some changes to your first script, which may be helpful for you in the future.
Instead of:
game.Players[tostring(player.Name)].PlayerGui.Garage.menu.Visible = true
try
if player.PlayerGui:FindFirstChild("Garage") then
player.PlayerGui.Garage.menu.Visible = true
end
There is no need to access game.Players since the MouseClick event already returns the player object that clicked the button. I use FindFirstChild which checks if the Garage GUI exists. This can prevent potential errors from occurring and is often good practice.
Hopefully this helps, please follow up if you're still having issues.

Related

MacOS not responding to MPRemoteCommandCenter commands in the background

I am writing an application for my own purposes that aims to get play pause events no matter what is going on in the system. I have gotten this much working
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.togglePlayPauseCommand.isEnabled = true
commandCenter.togglePlayPauseCommand.addTarget { (MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus in
print("Play Pause Command")
return .success
}
commandCenter.nextTrackCommand.isEnabled = true
commandCenter.nextTrackCommand.addTarget { (MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus in
print("NextTrackCommand")
return .success
}
commandCenter.previousTrackCommand.isEnabled = true
commandCenter.previousTrackCommand.addTarget { (MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus in
print("previousTrackCommand")
return .success
}
commandCenter.playCommand.isEnabled = true
commandCenter.playCommand.addTarget { (MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus in
print("playCommand")
return .success
}
MPNowPlayingInfoCenter.default().playbackState = .playing
Most of those methods are there because apparently you will not get any notifications without having nextTrackCommand or previousTrackCommand or playCommand implemented.
Anyways my one issue is that as soon as you open another application that uses audio these event handlers stop getting called and I cant find a way to detect and fix this.
I would normally try doing AVAudioSession things to state this as a background application however that does not seem to work. Any ideas on how I can get playpause events no matter what state the system is in?
I would like to be able to always listen for these events OR get an indication of when someone else has taken control of the audio? Perhaps even be able to re-subscribe to these play pause events.
There's an internal queue in the system which contains all the audio event subscribers. Other applications get on top of it when you start using them.
I would like to be able to always listen for these events
There's no API for that but there's a dirty workaround. If I understand your issue correctly, this snippet:
MPNowPlayingInfoCenter.default().playbackState = .paused
MPNowPlayingInfoCenter.default().playbackState = .playing
must do the trick for you if you run it in a loop somewhere in your application.
Note that this is not 100% reliable because:
If an event is generated before two subsequent playbackState state changes right after you've switched to a different application, it would still be catched by the application in the active window;
If another application is doing the same thing, there would be a constant race condition in the queue, with unpredictable outcome.
References:
Documentation for playbackState is here;
See also a similar question;
See also a bug report for mpv with a similar
issue (a pre-MPRemoteCommandCenter one, but still very valuable)
OR get an indication of when someone else has taken control of the audio
As far as I know there's no public API for this in macOS.

Test Complete Automation - Issue with waiting for an object to load

Background:
I have a JAVA application on which we run our Test Complete scripts(We have recently moved from UFT to TestComplete, so TC is a bit new for us). The scripting language used is VBScript.
Issue:
In order to handle the slow application behavior, I have created a function which waits for an object to get loaded and become visible on the screen before any operation is performed on that object. But, at times, the function does not work. By this, I mean that even though the object is loaded and is visible on the screen, the function still keeps on waiting for the object i.e., uiObject.exists keeps on returning false due to which it keeps on waiting until the timeout value is reached. Has someone here faced this issue before?
Paramter values passed:
uiObject = Aliases.ParentObj.Login_Window
intMaxTimeOut = 120
Code
'============================================================================================================
'Function Name: fn_waitForObject
'Purpose: To wait for an object to exist and become visible on screen
'Creation Date: 04-06-2018
'Return type: true, if the object exists and is visible; false, if the object doesn't exist
'Parameters: uiObject - The object for which the script waits to get visible on screen
' intMaxTimeOut - Maximum timeout in seconds
'============================================================================================================
function fn_waitForObject(uiObject,intMaxTimeOut)
Dim intCounter : intCounter = 0
Do While (intCounter < intMaxTimeOut)
If uiObject.exists then
Exit Do
Else
intCounter = intCounter + 1
delay 1000
End If
Loop
'If the object exists, make sure that it is visible on screen
If uiObject.exists then
Do While (intCounter < intMaxTimeOut)
If uiObject.visibleonscreen then
Log.Message "The object """&uiObject.toString&""" exists and is visible on screen"
Exit Do
Else
intCounter = intCounter + 1
delay 1000
End If
Loop
End If
fn_waitForObject = uiObject.visibleonscreen
End Function
Object Spy
Maybe the information on this link can help you!
whats is the difference between UIObject and UIObject2 other than UIAutomator 2.0 version name?
What is the actual error saying in TC?
Have you seen this link? https://support.smartbear.com/testcomplete/docs/app-objects/common-tasks/waiting-process-or-window-activation.html
I would also suggest trying to use the record keyword test, then convert it to script
For now you could increase your max timeout value, but your while loop will still have a hard upper limit. I recommend using one of the methods listed in the article above, as they will make TestComplete wait until your process/objects have fully loaded, no matter how much time has passed. That way, you won't run into your current problem anymore.
It is the Name Mapping creating a 2nd version of the same object.
Go into the Name Mapping and edit the properties to only use static properties, so new versions of the same UIObject are not being created.

Non helpfull error message Calabash with page objects pattern

I'm currently using Calabash framework to automate functional testing for a native Android and IOS application. During my time studying it, I stumbled upon this example project from Xamarin that uses page objects design pattern which I find to be much better to organize the code in a Selenium fashion.
I have made a few adjustments to the original project, adding a file called page_utils.rb in the support directory of the calabash project structure. This file has this method:
def change_page(next_page)
sleep 2
puts "current page is #{current_page_name} changing to #{next_page}"
#current_page = page(next_page).await(PAGE_TRANSITION_PARAMETERS)
sleep 1
capture_screenshot
#current_page.assert_info_present
end
So in my custom steps implementation, when I want to change the page, I trigger the event that changes the page in the UI and update the reference for Calabash calling this method, in example:
#current_page.click_to_home_page
change_page(HomePage)
PAGE_TRANSITION_PARAMETERS is a hash with parameters such as timeout:
PAGE_TRANSITION_PARAMETERS = {
timeout: 10,
screenshot_on_error: true
}
Just so happens to be that whenever I have a timeout waiting for any element in any screen during a test run, I get a generic error message such as:
Timeout waiting for elements: * id:'btn_ok' (Calabash::Android::WaitHelpers::WaitError)
./features/support/utils/page_utils.rb:14:in `change_page'
./features/step_definitions/login_steps.rb:49:in `/^I enter my valid credentials$/'
features/04_support_and_settings.feature:9:in `And I enter my valid credentials'
btn_ok is the id defined for the trait of the first screen in my application, I don't understand why this keeps popping up even in steps ahead of that screen, masking the real problem.
Can anyone help getting rid of this annoyance? Makes really hard debugging test failures, specially on the test cloud.
welcome to Calabash!
As you might be aware, you'll get a Timeout waiting for elements: exception when you attempt to query/wait for an element which can't be found on the screen. When you call page.await(opts), it is actually calling wait_for_elements_exist([trait], opts), which means in your case that after 10 seconds of waiting, the view with id btn_ok can't be found on the screen.
What is assert_info_present ? Does it call wait_for_element_exists or something similar? More importantly, what method is actually being called in page_utils.rb:14 ?
And does your app actually return to the home screen when you invoke click_to_home_page ?
Unfortunately it's difficult to diagnose the issue without some more info, but I'll throw out a few suggestions:
My first guess without seeing your application or your step definitions is that #current_page.click_to_home_page is taking longer than 10 seconds to actually bring the home page back. If that's the case, simply try increasing the timeout (or remove it altogether, since the default is 30 seconds. See source).
My second guess is that the element with id btn_ok is not actually visible on screen when your app returns to the home screen. If that's the case, you could try changing the trait definition from * id:'btn_ok' to all * id:'btn_ok' (the all operator will include views that aren't actually visible on screen). Again, I have no idea what your app looks like so it's hard to say.
My third guess is it's something related to assert_info_present, but it's hard to say without seeing the step defs.
On an unrelated note, I apologize if our sample code is a bit outdated, but at the time of writing we generally don't encourage the use of #current_page to keep track of a page. Calabash was written in a more or less stateless manner and we generally encourage step definitions to avoid using state wherever possible.
Hope this helps! Best of luck.

Watir webdriver - click an element and not wait for load

I have 2 sides in my page, clicking one of the buttons on the left side, refreshes the right side.
Now I want to see whether the site gets stuck if i click the buttons too fast while not letting the right side to fully load.
Right now watir waits for the click command to return, so the test doesnt do what it should:
arr = ["div1", "div2", "div3"]
for i in 1..20
print "#{i}\r"
choise = arr.sample
b.div(:id=>choise).click
end
Any way to make it send the command and return without any delays?
Are you getting the same result in multiple browsers?
The spec (which may or may not be implemented or implemented the same way by the different browsers), says that webdriver prevents other commands from being executed while there are outstanding network requests. Though, it also says it should wait for document.readyState to be present for the frame currently handling the commands, so it is unclear if the outstanding network request is supposed to apply to only the current frame or to all frames.
But since Webdriver is designed for commands to be handled in a synchronous manner, it is likely just not designed to do what you are trying to do.
Not sure but you can try with javascripts:
#browser.execute_script("document.getElementById('choise').click")
b.div(:id => 'choise').exist? - to check exist it or aren't
b.div(:id => 'choise').click
I think titusfortner is right. But look this answer.
begin
Timeout::timeout(10) do
# perform actions that may hang here
end
rescue Timeout::Error => msg
put "Recovered from Timeout"
end

MATLAB event and infinite sleeping or checking loop

I need to perform data analysis on files in a directory as they come in.
I'd like to know, if it is better,
to implement an event listener on the directory, and start the analysis process when activated. Then having the program go into sleep forever: while(true), sleep(1e10), end
or to have a loop polling for changes and reacting.
I personally prefer the listeners way, as one is able to start the analysis twice on two new files coming in NEARLY the same time but resulting in two events. While the other solution might just handle the first one and after that finds the second new data.
Additional idea for option 1: Hiding the matlab GUI by calling frames=java.awt.Frame.getFrames and setting frames(index).setVisible(0) on the index matching the com.mathworks.mde.desk.MLMainFrame-frame. (This idea is taken from Yair Altman)
Are there other ways to realize such things?
In this case, (if you are using Windows), the best way is to use the power of .NET.
fileObj = System.IO.FileSystemWatcher('c:\work\temp');
fileObj.Filter = '*.txt';
fileObj.EnableRaisingEvents = true;
addlistener(fileObj,'Changed',#eventhandlerChanged);
There are different event types, you can use the same callback for them, or different ones:
addlistener(fileObj, 'Changed', #eventhandlerChanged );
addlistener(fileObj, 'Deleted', #eventhandlerChanged );
addlistener(fileObj, 'Created', #eventhandlerChanged );
addlistener(fileObj, 'Renamed', #eventhandlerChanged );
Where eventhandlerChanged is your callback function.
function eventhandlerChanged(source,arg)
disp('TXT file changed')
end
There is no need to use sleep or polling. If your program is UI based, then there is nothing else to do, when the user closes the figure, the program has ended. The event callbacks are executed exactly like button clicks. If your program is script-like, you can use an infinite loop.
More info in here: http://www.mathworks.com/help/matlab/matlab_external/working-with-net-events-in-matlab.html

Resources